Skip to main content
Tekton emits events to notify external systems about TaskRun and PipelineRun execution status. Two event types are supported: Kubernetes events and CloudEvents.

Kubernetes Events

Tekton controllers emit standard Kubernetes events that can be retrieved using kubectl describe.

TaskRun Events

TaskRuns emit events for the following reasons:
Started
event
Emitted when the TaskRun is first picked by the reconciler from the work queue (after successful webhook validation).Does not indicate Step execution. Steps execute only after:
  • Task and resource validation succeeds
  • Associated Conditions checks succeed
  • Pod scheduling succeeds
Succeeded
event
Emitted when all steps in the TaskRun execute successfully, including Tekton-injected post-steps.
Failed
event
Emitted when:
  • A Step fails
  • TaskRun times out
  • TaskRun is cancelled
  • Validation fails (TaskRun cannot execute)

PipelineRun Events

PipelineRuns emit events for the following reasons:
Started
event
Emitted when the PipelineRun is first picked by the reconciler from the work queue (after successful webhook validation).Does not indicate Step execution. Steps execute after validation succeeds for the Pipeline and all associated Tasks and Resources.
Running
event
Emitted when the PipelineRun passes validation and begins execution.
Succeeded
event
Emitted when all Tasks reachable via the DAG execute successfully.
Failed
event
Emitted when:
  • A Task fails
  • PipelineRun times out
  • PipelineRun is cancelled
  • Validation fails (PipelineRun cannot execute)

Viewing Kubernetes Events

View events for a TaskRun:
kubectl describe taskrun my-taskrun
View events for a PipelineRun:
kubectl describe pipelinerun my-pipelinerun
View all events in a namespace:
kubectl get events -n tekton-pipelines --sort-by='.lastTimestamp'

CloudEvents

When configured with a sink, Tekton emits CloudEvents for run lifecycle changes.

CloudEvents Configuration

Configure CloudEvents in the config-events ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-events
  namespace: tekton-pipelines
data:
  formats: "tektonv1"
  sink: "https://events.example.com/tekton"
formats
string
default:"tektonv1"
Comma-separated list of event formats. Currently only tektonv1 is supported.
An empty string is not valid. To disable events, omit the sink.
sink
string
Event sink URL for TaskRun, PipelineRun, and CustomRun events.
data:
  sink: "https://my-sink-url.example.com"
This setting supersedes default-cloud-events-sink from the config-defaults ConfigMap.

Legacy Configuration

The deprecated config-defaults configuration is still supported:
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-defaults
  namespace: tekton-pipelines
data:
  default-cloud-events-sink: "https://my-sink-url"
The default-cloud-events-sink option in config-defaults is deprecated and will be removed. Use the config-events ConfigMap instead.

CustomRun Events

CloudEvents for CustomRuns require additional configuration:
apiVersion: v1
kind: ConfigMap
metadata:
  name: feature-flags
  namespace: tekton-pipelines
data:
  send-cloudevents-for-runs: "true"
CustomRun CloudEvents use an ephemeral cache to avoid duplicates. Controller restarts reset the cache and may result in duplicate events.

CloudEvent Types

Tekton emits the following CloudEvent types:
ResourceEventEvent Type
TaskRunStarteddev.tekton.event.taskrun.started.v1
TaskRunRunningdev.tekton.event.taskrun.running.v1
TaskRunCondition Change while Runningdev.tekton.event.taskrun.unknown.v1
TaskRunSucceededdev.tekton.event.taskrun.successful.v1
TaskRunFaileddev.tekton.event.taskrun.failed.v1
PipelineRunStarteddev.tekton.event.pipelinerun.started.v1
PipelineRunRunningdev.tekton.event.pipelinerun.running.v1
PipelineRunCondition Change while Runningdev.tekton.event.pipelinerun.unknown.v1
PipelineRunSucceededdev.tekton.event.pipelinerun.successful.v1
PipelineRunFaileddev.tekton.event.pipelinerun.failed.v1
RunStarteddev.tekton.event.run.started.v1
RunRunningdev.tekton.event.run.running.v1
RunSucceededdev.tekton.event.run.successful.v1
RunFaileddev.tekton.event.run.failed.v1

CloudEvent Format

CloudEvents follow the CloudEvents specification.

HTTP Headers

Context fields are included as HTTP headers:
Ce-Id: 77f78ae7-ff6d-4e39-9d05-b9a0b7850527
Ce-Source: /apis/tekton.dev/v1beta1/namespaces/default/taskruns/curl-run-6gplk
Ce-Specversion: 1.0
Ce-Subject: curl-run-6gplk
Ce-Time: 2021-01-29T14:47:58.157819Z
Ce-Type: dev.tekton.event.taskrun.unknown.v1
Content-Type: application/json

Payload

The payload is JSON with a single root key (taskRun or pipelineRun) containing the complete resource spec and status:
{
  "taskRun": {
    "metadata": {
      "name": "curl-run-6gplk",
      "namespace": "default",
      "creationTimestamp": "2021-01-29T14:47:57Z",
      "labels": {
        "app.kubernetes.io/managed-by": "tekton-pipelines",
        "tekton.dev/task": "curl"
      }
    },
    "spec": {
      "params": [
        {
          "name": "url",
          "value": "https://example.com"
        }
      ],
      "serviceAccountName": "default",
      "taskRef": {
        "kind": "Task",
        "name": "curl"
      },
      "timeout": "1h0m0s"
    },
    "status": {
      "conditions": [
        {
          "lastTransitionTime": "2021-01-29T14:47:58Z",
          "message": "pod status \"Initialized\":\"False\"",
          "reason": "Pending",
          "status": "Unknown",
          "type": "Succeeded"
        }
      ],
      "podName": "curl-run-6gplk-pod",
      "startTime": "2021-01-29T14:47:57Z"
    }
  }
}

Event Delivery

CloudEvents are sent in a parallel routine to allow retries without blocking the reconciler:
  • Events are sent when the Succeeded condition changes (state, reason, or message)
  • Retries use exponential back-off strategy
  • Events are not guaranteed to arrive in order due to retries

Event Sink Implementation Examples

Simple HTTP Sink

from flask import Flask, request
import json

app = Flask(__name__)

@app.route('/tekton', methods=['POST'])
def handle_event():
    headers = dict(request.headers)
    event_type = headers.get('Ce-Type')
    event_id = headers.get('Ce-Id')
    
    payload = request.json
    
    print(f"Received event: {event_type} (ID: {event_id})")
    print(json.dumps(payload, indent=2))
    
    return '', 204

if __name__ == '__main__':
    app.run(port=8080)

Knative Event Sink

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: tekton-event-handler
  namespace: default
spec:
  template:
    spec:
      containers:
      - image: gcr.io/my-project/event-handler:latest
        env:
        - name: EVENT_SOURCE
          value: "tekton-pipelines"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-events
  namespace: tekton-pipelines
data:
  sink: "http://tekton-event-handler.default.svc.cluster.local"

Filtering Events

To process only specific event types in your sink:
app.post('/tekton', (req, res) => {
  const eventType = req.headers['ce-type'];
  
  // Only process failed events
  if (eventType.includes('.failed.')) {
    const resource = req.body.taskRun || req.body.pipelineRun;
    console.log(`Failed: ${resource.metadata.name}`);
    
    // Send notification, create ticket, etc.
  }
  
  res.status(204).send();
});

Troubleshooting

No Events Received

  1. Verify sink is configured:
    kubectl get cm config-events -n tekton-pipelines -o yaml
    
  2. Check controller logs:
    kubectl logs -n tekton-pipelines -l app=tekton-pipelines-controller
    
  3. Test sink connectivity from cluster:
    kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
      curl -v https://your-sink-url
    

Duplicate Events

Duplicate events can occur due to:
  • Controller restarts (CustomRun cache reset)
  • Network retry logic
  • Event delivery retries
Implement idempotency in your event handler using the Ce-Id header.

Missing Events

Events may be missed if:
  • Sink is unavailable during event emission
  • Sink returns non-2xx status codes
  • Network issues prevent delivery
Implement proper error handling and consider using a message queue for critical events.

Best Practices

  1. Use idempotent event handlers - Events may be delivered more than once
  2. Handle all event types - Don’t assume only specific types will be received
  3. Implement proper error handling - Return appropriate HTTP status codes
  4. Use async processing - Respond quickly (< 30s) to avoid timeouts
  5. Log event IDs - Use Ce-Id for debugging and deduplication
  6. Monitor sink availability - High availability sinks prevent event loss
  7. Consider event ordering - Don’t rely on events arriving in chronological order

Build docs developers (and LLMs) love