Runs
Start a run of a pipeline, pin a version, follow the log of each job, and cancel a run.
Last updated
On this page
Description and operation
General
A run is one execution of one version of a pipeline. A start by hand uses the newest version, or the version that you name. Each run records what it used, so you can see later what ran and why.
| Field | Meaning |
|---|---|
id | The identity of the run, for example 1760400000000-0a1b2c. Ids sort by start time. |
number | The number of the run for this pipeline, from 1. |
pipelineVersion, definitionSha256 | The version that the run used, and the hash of its definition. |
event | What started the run: manual, schedule, webhook or pipeline. |
requestedBy | Your handle, or schedule, webhook or pipeline NAME for a trigger. |
inputs | The value of each input: the one given, else the default. |
environment | The environment that the start request named, or null. |
state, detail | The state of the run, and the cause when it did not succeed. See States. |
jobs | One entry for each job and matrix instance, with its own state. |
after, triggered | The run whose end started this run, and the runs that this run started. See After another pipeline. |
requestedAtMs, startedAtMs, finishedAtMs | The times, in milliseconds since 1970, when the run was requested, started and ended. |
cancelRequested | true after a cancel of the run. |
claimedBy, leaseExpiresMs | The worker that holds the run, and when its claim lapses. |
definition | The definition of the version. Only a read of one run returns it, while the version exists. |
A run keeps the definition that it started with. A later save does not change a run that exists. The full run document is in the pipelines API.
To do these tasks with an AI agent, see Agentic workflows – General.
Start options
| Option | Meaning |
|---|---|
version | The version to run. The default is the newest version at the time of the call. |
inputs | Values for the declared inputs. See Inputs. |
environment | Run every job that names no environment in this shared environment. |
clone | Run those jobs in a copy of this environment, made for the run. Use only one of environment and clone. |
The raw API has no clone key. It takes environment as a name, or as {"clone": "name"}. The SDKs and --clone build the second form.
The start call plans the run at once and answers 202 with the run in queued. If the version cannot run, the call answers 422 with one line for each problem, and records nothing. For environments, see Secrets, registries and environments.
Logs
Each job has one log that holds its output and its error output. The log shows ▶ and the step name before each step, and a last line ■ with the cause when the job did not succeed. You read a log from a byte offset, so a program follows a running job by reading again from next. One answer holds at most 1 MiB. The SDK methods logs and follow do this for you.
A log stops at 8 MiB with the line [log truncated: past 8 MiB]. Secret values in a log show as ***. See Masking.
Cancel
A cancel of a queued run ends it at once. A cancel of a running run sets cancelRequested. The platform then stops each running job and cancels the pending jobs. A cancel of a finished run answers 409.
Retention
The platform deletes a run record 90 days after the run ends. A job log is deleted 90 days after the run started. After that, a read of the log returns the single line log expired: job logs are kept for 90 days.
Tasks
Start a run of a pinned version
Reason for the task: Run a known version of a pipeline, with the inputs and the environment that you choose.
Job set-up
- Access: you. For a team, an active member.
- Conditions: the pipeline
refreshhas version 2. See Show the versions of a pipeline. - References:
POST /v1/pipelines/{owner}/{pipeline}/runs, SDKpipelines.run.
Procedure
Start the run. Leave out
versionto run the newest version.run = kl.pipelines.run(owner="acme", pipeline="refresh", version=2, inputs={"day": "2026-10-21"})print(run.id, run.pipeline_version, run.state)const run = await kl.pipelines.run({ owner: "acme", pipeline: "refresh", version: 2, inputs: { day: "2026-10-21" } });console.log(run.id, run.doc.pipelineVersion, run.state);run, err := kl.Pipelines.Run(kloudlite.RunPipeline{ Owner: "acme", Pipeline: "refresh", Version: 2, Inputs: map[string]string{"day": "2026-10-21"},})if err != nil { log.Fatal(err)}fmt.Println(run.ID, run.PipelineVersion, run.State)run = kl.pipelines.run(owner: "acme", pipeline: "refresh", version: 2, inputs: { "day" => "2026-10-21" })puts run.id, run.pipeline_version, run.statevar run = kl.pipelines().run(new Kloudlite.RunPipeline().owner("acme").pipeline("refresh").version(2).input("day", "2026-10-21"));System.out.println(run.id() + " " + run.pipelineVersion() + " " + run.state());kloudlite pipelines run acme/refresh --version 2 --input day=2026-10-21Add
clone="staging"to run the jobs in a copy of the environmentstaging, orenvironment="staging"to use it as it is.
Close-out
- Make sure that
pipelineVersionis2and that the state isqueuedorrunning.
List the runs of a pipeline
Reason for the task: Find a run, for example the newest run that a schedule started.
Job set-up
- Access: you. For a team, an active member.
- References:
GET /v1/pipelines/{owner}/{pipeline}/runs, SDKpipelines.runs.
Procedure
Show the newest runs. The default is 50 runs, and the maximum is 200.
for r in kl.pipelines.runs(owner="acme", pipeline="refresh", limit=10): print(r.number, r.id, r.event, r.state)for (const r of await kl.pipelines.runs({ owner: "acme", pipeline: "refresh", limit: 10 })) console.log(r.number, r.id, r.doc.event, r.state);runs, err := kl.Pipelines.Runs(kloudlite.ListRuns{Owner: "acme", Pipeline: "refresh", Limit: 10})if err != nil { log.Fatal(err)}for _, r := range runs { fmt.Println(r.Number, r.ID, r.Event, r.State)}kl.pipelines.runs(owner: "acme", pipeline: "refresh", limit: 10).each do |r| puts [r.number, r.id, r.event, r.state].join(" ")endfor (var r : kl.pipelines().runs(new Kloudlite.ListRuns().owner("acme").pipeline("refresh").limit(10))) System.out.println(r.number() + " " + r.id() + " " + r.event() + " " + r.state());kloudlite pipelines runs acme refresh --limit 10
Close-out
- Make sure that the list starts with the newest run.
Show the state of a run and its jobs
Reason for the task: Find out if a run succeeded, and which job or step failed.
Job set-up
- Access: you. For a team, an active member.
- Conditions: you know the
idof the run. See List the runs of a pipeline. - References:
GET /v1/pipelines/{owner}/{pipeline}/runs/{id}, SDKpipelines.get_run.
Procedure
Read the run, then show its state and the state of each job.
run = kl.pipelines.get_run(owner="acme", pipeline="refresh", run="1760400000000-0a1b2c")print(run.state, run.detail)for j in run.jobs: print(j["key"], j["state"], j.get("failedStep"), j.get("detail"))const run = await kl.pipelines.getRun({ owner: "acme", pipeline: "refresh", run: "1760400000000-0a1b2c" });console.log(run.state, run.doc.detail);for (const j of run.jobs) console.log(j.key, j.state, j.failedStep, j.detail);run, err := kl.Pipelines.GetRun(kloudlite.GetRun{Owner: "acme", Pipeline: "refresh", Run: "1760400000000-0a1b2c"})if err != nil { log.Fatal(err)}fmt.Println(run.State, run.Detail)for _, j := range run.Jobs { fmt.Println(j.Key, j.State, j.FailedStep, j.Detail)}run = kl.pipelines.get_run(owner: "acme", pipeline: "refresh", run: "1760400000000-0a1b2c")puts run.state, run.detailrun.jobs.each { |j| puts j.values_at("key", "state", "failedStep", "detail").join(" ") }var run = kl.pipelines().getRun(new Kloudlite.GetRun().owner("acme").pipeline("refresh").run("1760400000000-0a1b2c"));System.out.println(run.state() + " " + run.detail());for (var j : run.jobs()) System.out.println(j.get("key") + " " + j.get("state") + " " + j.get("failedStep"));kloudlite pipelines get-run acme refresh 1760400000000-0a1b2c
Close-out
- Make sure that the state is
success. If it isfailure, readdetailof the run andfailedStepof the failed job.
Read the log of a job
Reason for the task: Read the output of a job, while it runs or after it ended.
Job set-up
- Access: you. For a team, an active member.
- Conditions: you have the run handle from task 003.
- References:
GET …/jobs/{index}/logs, SDKRun.logs,Run.follow.
Procedure
Read the whole log of the job
load. Use the key of the job, or its index injobs.print(run.logs(job="load"))console.log(await run.logs({ job: "load" }));out, err := run.Logs("load")if err != nil { log.Fatal(err)}fmt.Print(out)puts run.logs(job: "load")System.out.print(run.logs("load"));kloudlite pipelines logs acme refresh 1760400000000-0a1b2c loadRead the log of a running job as it grows. The call ends when the job ends.
for chunk in run.follow(job="load"): print(chunk, end="")for await (const chunk of run.follow({ job: "load" })) process.stdout.write(chunk);err = run.Follow(kloudlite.FollowLogs{Job: "load"}, func(chunk string) bool { fmt.Print(chunk) return true})if err != nil { log.Fatal(err)}run.follow(job: "load") { |chunk| print chunk }run.follow("load").forEach(System.out::print);kloudlite pipelines logs acme refresh 1760400000000-0a1b2c load --follow
Close-out
- Make sure that the log shows a
▶line for each step of the job.
Cancel a run
Reason for the task: Stop a run that is not needed, and release its sandboxes.
Job set-up
- Access: you. For a team, an active member.
- Conditions: the run is
queuedorrunning. - References:
POST …/runs/{id}/cancel, SDKRun.cancel,Run.wait.
Procedure
Send the cancel, then wait for the run to end.
run.cancel()print(run.wait())await run.cancel();console.log(await run.wait());if err := run.Cancel(); err != nil { log.Fatal(err)}state, err := run.Wait(kloudlite.WaitRun{})if err != nil { log.Fatal(err)}fmt.Println(state)run.cancelputs run.waitrun.cancel();System.out.println(run.waitFor());kloudlite pipelines cancel-run acme refresh 1760400000000-0a1b2ckloudlite pipelines wait-run acme refresh 1760400000000-0a1b2c
Close-out
- Make sure that the final state is
cancelled, and that no job isrunning.
Troubleshooting
| Symptom | Possible cause | Corrective action |
|---|---|---|
422 with pipeline refresh cannot run: and a list of lines | An input or a secret is wrong. Each line names the cause. | Correct each cause and start again. See Triggers and inputs. |
404 with version 2 of refresh is gone | The version was deleted. | Start the newest version, or another version that is listed. |
400 with environment is empty | environment is an empty name, also in {"clone": ""} or --clone. | Give the name of an environment. |
409 with this run has already finished | The run ended before the cancel. | None. Read the final state of the run. |
404 with not found for a run | The id is wrong, or the run belongs to another pipeline. Run records are deleted 90 days after the run ends. | Check the owner, the pipeline and the id. |
The run stays queued | No worker has taken the run yet. | Wait, then show the run again. |
A job shows restarted: the worker running it was lost | The worker that ran the job stopped. Another worker runs the job again from the start. | None. Wait for the run to end. |
The log is log expired: job logs are kept for 90 days | The run started more than 90 days ago. | None. The run record shows the states. |
The log ends with [log truncated: past 8 MiB] | The job wrote more than 8 MiB. | Write less output, or write large output to a file. |
502 with the log could not be read | The log store did not answer. | Read the log again. |