diff --git a/app/models.py b/app/models.py
index 2f5597a5e3a309c8a161c1276233f098dfd60308..de1fb6980044ff9490da7f3a33fbae8d30a07b5f 100644
--- a/app/models.py
+++ b/app/models.py
@@ -967,6 +967,7 @@ class Task(db.Model):
     command = db.Column(db.Text)
     status = db.Column(db.Enum(JobStatus, name='job_status'))
     awx_job_id = db.Column(db.Integer)
+    exception = db.Column(db.Text)
     user_id = db.Column(db.Integer, db.ForeignKey('user_account.id'),
                         nullable=False, default=utils.fetch_current_user_id)
 
@@ -992,6 +993,7 @@ class Task(db.Model):
             'awx_job_id': self.awx_job_id,
             'awx_job_url': self.awx_job_url,
             'command': self.command,
+            'exception': self.exception,
             'user': str(self.user),
         }
 
diff --git a/app/tasks.py b/app/tasks.py
index c558b83016ee529b4d8e34256cffef1fe2da7b69..fba509724fef211573affb64fa4067e5ed844d6e 100644
--- a/app/tasks.py
+++ b/app/tasks.py
@@ -10,6 +10,7 @@ This module implements tasks to run.
 
 """
 import time
+import traceback
 import tower_cli
 from flask import current_app
 from rq import Worker, get_current_job
@@ -23,6 +24,19 @@ class TaskWorker(Worker):
     the task status in the CSEntry database
     """
 
+    def save_exception(self, job, *exc_info):
+        """Save the exception to the database
+
+        The exception is only saved if it occured before the AWX job was triggered.
+        If the AWX job failed, we can refer to the logs on AWX.
+        """
+        task = models.Task.query.get(job.id)
+        if task.awx_job_id is None:
+            # No AWX job was triggered. An exception occured before. Save it.
+            task.exception = self._get_safe_exception_string(
+                traceback.format_exception(*exc_info))
+            db.session.commit()
+
     def update_task_attribute(self, job, name, value):
         # The task is created after enqueueing the job.
         # If the job is processed very quickly, the task might
@@ -43,6 +57,7 @@ class TaskWorker(Worker):
     def move_to_failed_queue(self, job, *exc_info):
         self.update_task_attribute(job, 'ended_at', job.ended_at)
         self.update_task_attribute(job, 'status', models.JobStatus.FAILED)
+        self.save_exception(job, *exc_info)
         super().move_to_failed_queue(job, *exc_info)
 
     def handle_job_success(self, job, queue, started_job_registry):
diff --git a/app/templates/task/view_task.html b/app/templates/task/view_task.html
index 2530f33ad675d0350c666743e563073fdc7251d3..4a5afbb92ac21b5a2d685bb74ea6a2c657bdd942 100644
--- a/app/templates/task/view_task.html
+++ b/app/templates/task/view_task.html
@@ -28,6 +28,10 @@
         {% else %}
         <dd class="col-sm-9">{{ task.awx_job_id }}</dd>
         {% endif %}
+        {% if task.exception %}
+        <dt class="col-sm-3">Exception</dt>
+        <dd class="col-sm-9"><pre>{{ task.exception }}</pre></dd>
+        {% endif %}
         <dt class="col-sm-3">Command</dt>
         <dd class="col-sm-9">{{ task.command }}</dd>
         <dt class="col-sm-3">User</dt>
diff --git a/migrations/versions/a9442567c6dc_add_exception_to_task_table.py b/migrations/versions/a9442567c6dc_add_exception_to_task_table.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3d83798d56961115b8c50854ffbf85dbe9e2e07
--- /dev/null
+++ b/migrations/versions/a9442567c6dc_add_exception_to_task_table.py
@@ -0,0 +1,24 @@
+"""add exception to task table
+
+Revision ID: a9442567c6dc
+Revises: c0b8036078e7
+Create Date: 2018-07-03 07:17:03.718695
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'a9442567c6dc'
+down_revision = 'c0b8036078e7'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column('task', sa.Column('exception', sa.Text(), nullable=True))
+
+
+def downgrade():
+    op.drop_column('task', 'exception')