Job runs and logs
New to the SDK? Getting started shows how to connect and use it.
Job runs
JobRuns
The runs of one workspace, or of one job within it.
JobRuns.get()
get(*, id: str) -> JobRun
Return one run by id.
Job runs are addressed by uuid; to find one by number, filter
list() with number.
Arguments
| Name | Type | Description |
|---|---|---|
id | str | The run's uuid. |
Returns: JobRun — The run; awaitable in async mode.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
NotFound | No such run in this workspace. |
ScopeMissing | Reached without a workspace in scope. |
JobRuns.result()
result(*, id: str) -> JobResult
Read one run's declared result, without reading the run itself.
Arguments
| Name | Type | Description |
|---|---|---|
id | str | The run's uuid. |
Returns: JobResult — The result; awaitable in async mode.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
NotFound | No such run, or it declared no result — the platform answers the same either way. |
ScopeMissing | Reached without a workspace in scope. |
JobRuns.trace()
trace(*, id: str) -> JobResultTrace
Read one run's whole result, without reading the run itself.
Arguments
| Name | Type | Description |
|---|---|---|
id | str | The run's uuid. |
Returns: JobResultTrace — The whole result; awaitable in async mode.
Raises
| Exception | When |
|---|---|
ApiError | The result is too large to serve (code job_result_trace_too_large); result() still reads the summary fields. |
BadRequest | The request was rejected as invalid; message, code and fields say why. |
NotFound | No such run, or it declared no result — the platform answers the same either way. |
ScopeMissing | Reached without a workspace in scope. |
JobRuns.latest()
latest(*, job_id: str | None = None) -> JobRun
Return the most recent run.
Arguments
| Name | Type | Description |
|---|---|---|
job_id | str | None | Narrow to one job's runs. Omit to use the job in scope, or the whole workspace when there is none, which leaves out system jobs such as the dashboard. |
Returns: JobRun — The newest run; awaitable in async mode.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
NotFound | Nothing has run yet. |
ScopeMissing | Reached without a workspace in scope. |
JobRuns.count()
count(*, job_id: str | None = None) -> int
Return how many runs there have been, without fetching them.
Arguments
| Name | Type | Description |
|---|---|---|
job_id | str | None | Narrow to one job's runs. Omit to use the job in scope, or the whole workspace when there is none, which leaves out system jobs such as the dashboard. |
Returns: int — The count; awaitable in async mode. Saturates at 10,001.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
ScopeMissing | Reached without a workspace in scope. |
JobRuns.list()
list(
*,
job_id: str | None = None,
number: int | None = None,
limit: int | None = None,
offset: int = 0,
) -> Iterable[JobRun] | AsyncIterable[JobRun]
Yield runs newest first, paging lazily.
Platform errors are raised when iteration begins, not by this call.
Arguments
| Name | Type | Description |
|---|---|---|
job_id | str | None | Narrow to one job's runs. Omit to use the job in scope, or the whole workspace when there is none, which leaves out system jobs such as the dashboard. |
number | int | None | Keep only the run with this per-job number. Numbers repeat across jobs, so pair it with a job. |
limit | int | None | Return at most this many. None walks to the end, or to row 10,100, past which the platform does not page. |
offset | int | Skip this many, server-side. |
Returns: Iterable[JobRun] | AsyncIterable[JobRun] — An iterable of runs; async-iterable in async mode.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
ScopeMissing | Reached without a workspace in scope. |
ValueError | A negative limit or offset. |
JobRuns.cancel_all()
cancel_all(*, job_refs: Sequence[str], dry_run: bool = False) -> CancelReport
Stop whatever is running for the named jobs.
Addressed by job, not by run: cancels every pending, starting or
running run of the named jobs. A ref that names no job, or has nothing
running, is reported in not_running.
Arguments
| Name | Type | Description |
|---|---|---|
job_refs | Sequence[str] | The jobs whose runs to stop. |
dry_run | bool | Report what would be cancelled without stopping anything. |
Returns: CancelReport — What was cancelled and what was not running; awaitable in async mode.
Raises
| Exception | When |
|---|---|
ValueError | No job refs were given. |
ScopeMissing | Reached without a workspace in scope. |
JobRun
One execution of a job.
Attributes
| Name | Type | Description |
|---|---|---|
number | int | Number of the run within its job, counting up from 1; numbers repeat across jobs. |
id | str | Unique ID (a UUID). |
job_ref | str | Canonical job reference, unique per workspace. |
status | JobRunStatus | The status of the run. |
trigger | str | The trigger the run fired with, e.g. schedule:0 8 * * *, manual:jobs.my_job, job.success:jobs.upstream. |
profile | str | The name of the profile that was used for the run. |
started_at | datetime | None | When the run started; None until it has. |
finished_at | datetime | None | When the run finished; None until it has. |
duration_seconds | float | None | Duration of the run in seconds, possibly fractional; None until it has finished. |
max_run_time_seconds | int | None | Maximum allowed run duration in seconds for this job version. |
interval_start | datetime | None | Start of the interval the run processes; None for a job without intervals. |
interval_end | datetime | None | End of the interval the run processes; None for a job without intervals. |
pipeline_run_summaries | tuple[PipelineRunSummary, ...] | One entry per dlt pipeline name the run reported; a pipeline that ran more than once shows its latest report. In no particular order, and empty until telemetry has received the reports. |
previous_job_run_id | str | None | The upstream run whose completion started this one, through a job.success: / job.fail: trigger or a freshness dependency; None for a run started manually, by its own schedule, or by a trigger request. |
created_at | datetime | When it was created. |
finished | bool | Whether the status can still change. |
failed | bool | Whether the run finished without succeeding. |
JobRun.cancel()
cancel() -> JobRun
Ask the platform to stop this run.
The run moves to CANCELLING first, and to CANCELLED once it has
stopped.
Returns: JobRun — A fresh snapshot, usually CANCELLING rather than CANCELLED; awaitable in async mode.
Raises
| Exception | When |
|---|---|
BadRequest | The request was rejected as invalid; message, code and fields say why. |
Conflict | The current state does not allow the call, e.g. the workspace is archived; code and message say why. |
NotFound | The run no longer exists. |
JobRun.logs()
logs() -> Iterable[LogLine] | AsyncIterable[LogLine]
Read the run's stored log, oldest line first.
Lines arrive as the body does, so a long log is never held whole. The
platform consolidates a run's log after it ends, so this raises until
that has happened — stream_logs() is what follows a live run.
Platform errors are raised when iteration begins, not by this call.
Returns: Iterable[LogLine] | AsyncIterable[LogLine] — An iterable of log lines; async-iterable in async mode.
Raises
| Exception | When |
|---|---|
NotFound | The run has no stored log, either because it does not exist or because it has not been consolidated yet. |
ScopeMissing | Reached without a workspace in scope. |
JobRun.stream_logs()
stream_logs(*, follow: bool = True) -> Iterable[LogLine] | AsyncIterable[LogLine]
Follow the run's log live, until the run reaches a terminal status.
Read from the compute backend rather than from storage, so it works while a run is going and stops on its own when the run ends. The platform waits up to about a minute for a backend that has not started reporting yet. Platform errors are raised when iteration begins, not by this call.
Arguments
| Name | Type | Description |
|---|---|---|
follow | bool | Keep reading until the run ends. False replays what the backend has already reported and stops, which the platform marks only by going quiet — so a slow producer can end it early. |
Returns: Iterable[LogLine] | AsyncIterable[LogLine] — An iterable of log lines; async-iterable in async mode.
Raises
| Exception | When |
|---|---|
ApiError | The platform could not follow this run — it is unknown or its backend never reported, the backend does not support live logs, or the stream failed part-way. It reports these on an otherwise successful response, so this can be raised after some lines have already been yielded. |
ScopeMissing | Reached without a workspace in scope. |
JobRun.wait()
wait(*, timeout: float | None = None) -> JobRun
Poll until the run stops changing, and return what it ended as.
Settles on any terminal status, so a failed or cancelled run returns
rather than raises — read status to find out which. Checks
roughly every second at first and backs off to every ten, so a short run
is noticed almost at once and a long one is not polled thousands of
times.
Arguments
| Name | Type | Description |
|---|---|---|
timeout | float | None | Give up after this many seconds. None, the default, waits as long as the run takes. |
Returns: JobRun — A snapshot in a terminal status; awaitable in async mode.
Raises
| Exception | When |
|---|---|
NotFound | The run no longer exists. |
ScopeMissing | Reached without a workspace in scope. |
ValueError | A negative timeout. |
WaitTimeout | The run was still going when the deadline passed. It is unaffected — nothing cancels it — so this can be retried. |
JobRun.result()
result() -> JobResult
Read the structured result this run declared.
Returns: JobResult — The result; awaitable in async mode.
Raises
| Exception | When |
|---|---|
NotFound | The run declared none, which is the normal case for a job that reports no result — not a sign the run is missing. |
ScopeMissing | Reached without a workspace in scope. |
JobRun.trace()
trace() -> JobResultTrace
Read the whole result this run delivered, trace included.
Returns: JobResultTrace — The whole result; awaitable in async mode.
Raises
| Exception | When |
|---|---|
ApiError | The result is too large to serve (code job_result_trace_too_large); result() still reads the summary fields. |
NotFound | The run declared no result, which is the normal case for a job that reports none — not a sign the run is missing. |
ScopeMissing | Reached without a workspace in scope. |
CancelledRun
One run a bulk cancel stopped.
Attributes
| Name | Type | Description |
|---|---|---|
job_ref | str | Job reference of the cancelled run. |
job_run_id | str | ID of the cancelled run. |
job_run_number | int | Number of the run within its job; numbers repeat across jobs. |
previous_status | JobRunStatus | Status of the run when the cancel request arrived. |
CancelReport
What a bulk cancel did.
Attributes
| Name | Type | Description |
|---|---|---|
cancelled | tuple[CancelledRun, ...] | The runs asked to stop (now cancelling), or that would be in a dry run. |
not_running | tuple[str, ...] | Job refs that had nothing to stop, which is not an error. |
JobResult
The structured result a run declared.
A run yields at most one, and most do not: a plain pipeline job declares
none, where an agent job reports its own outcome here. The agent fields are
None for any other kind of result.
Attributes
| Name | Type | Description |
|---|---|---|
job_run_id | str | Job run that declared the result. |
job_ref | str | The job that declared the result. |
result_type | str | job.{category}.{name}, for example job.background_agent.{name}. |
engine_version | int | Result format version; 1 when not declared. |
result | Any | The job's declared output. Shape is job-defined. |
agent_status | str | None | The agent's self-report, which may legitimately disagree with the run's own status: a failed agent inside a succeeded run is normal. |
summary | str | None | Model-authored markdown, unbounded. Untrusted — render as user content. |
model | str | None | Model the agent ran with. None when the result carries no agent trace, as for non-agent jobs. |
loop_type | str | None | Agent loop that ran. None when the result carries no agent trace, as for non-agent jobs. |
input_tokens | int | None | Input tokens the agent used. None when the result carries no agent trace, as for non-agent jobs. |
output_tokens | int | None | Output tokens the agent used. None when the result carries no agent trace, as for non-agent jobs. |
total_tokens | int | None | Total tokens the agent used. None when the result carries no agent trace, as for non-agent jobs. |
cost_usd | str | None | Cost in USD the agent reported, as a decimal string. None when the result carries no agent trace, as for non-agent jobs. |
turn_count | int | None | Number of turns the agent took. None when the result carries no agent trace, as for non-agent jobs. |
stop_reason | str | None | Why the agent stopped. None when the result carries no agent trace, as for non-agent jobs. |
created_at | datetime | When the result was first stored, UTC. |
updated_at | datetime | When the result was last stored, UTC. |
JobResultTrace
The whole job result a run delivered, as the job sent it.
JobResult carries the summary fields; this carries the whole result
as the job delivered it, which is where an agent's per-turn tool calls live.
Attributes
| Name | Type | Description |
|---|---|---|
job_run_id | str | The run that declared it. |
result | Mapping[str, Any] | The result exactly as delivered — the declared output and, for an agent, its trace: turns and the tools each called, token counts, stop reason. Left opaque: the platform stores and returns it verbatim and declares no shape for it. |
PipelineRunSummary
One dlt pipeline a run executed, as telemetry reported it.
A run executes whatever pipelines its job calls, so a job that loads two sources reports two. A run carries one entry per dlt pipeline name it reported; a pipeline that ran more than once shows its latest report. Telemetry fills this in after the pipeline reports, so a run that has just started carries none, and a run whose job never reached a pipeline carries none for good.
Attributes
| Name | Type | Description |
|---|---|---|
pipeline_name | str | Name of the dlt pipeline. |
pipeline_run_id | str | None | Telemetry ID of the pipeline run. |
transaction_id | str | None | Transaction ID of the pipeline run. |
destination_name | str | None | Name of the destination the pipeline wrote to. |
dataset_name | str | None | Name of the dataset the pipeline wrote to. |
status | str | None | What the pipeline run ended as. Free-form: it is dlt's own wording, not JobRunStatus. |
total_rows | int | None | Total number of rows loaded by the pipeline. |
duration_ms | int | None | Duration of the pipeline run in milliseconds. |
started_at | datetime | None | When the pipeline run started. |
finished_at | datetime | None | When the pipeline run finished. |
JobRunStatus
Where a run has got to.
Members
| Member | Value | Description |
|---|---|---|
PENDING | 'pending' | Accepted, not yet started. |
STARTING | 'starting' | Being placed on a compute backend. |
RUNNING | 'running' | Executing. |
CANCELLING | 'cancelling' | Cancellation asked for, not yet effective. |
COMPLETED | 'completed' | Finished successfully. |
FAILED | 'failed' | Finished unsuccessfully. |
CANCELLED | 'cancelled' | Stopped on request, or because it exceeded its maximum run time. |
SKIPPED | 'skipped' | Recorded without running. A start the platform declines is normally reported through TriggerStatus and creates no run. |
UNKNOWN | 'unknown' | A status this SDK version does not know. |
Logs
LogLine
One line a run emitted.
Attributes
| Name | Type | Description |
|---|---|---|
content | str | Contents of the log message. |
line_num | int | Position of the line in the run's log. |
source | LogSource | Who emitted the line. |
stage | LogStage | Stage of the run the line belongs to: build (installing dependencies before the job starts) or run (the job's execution). |
io_stream | LogIoStream | Stream the line was written to: stdout, stderr, or other (a provider's info channel, or a line stored before streams were kept). |
reported_at | datetime | Timestamp when the log was reported. |
LogIoStream
The stream a log line was written to.
Members
| Member | Value | Description |
|---|---|---|
STDOUT | 'stdout' | Standard output. |
STDERR | 'stderr' | Standard error. |
OTHER | 'other' | Neither: an info channel of the compute backend, or a line stored before the stream was recorded. |
UNKNOWN | 'unknown' | A stream this SDK version does not know. |
LogSource
Who emitted a log line.
Members
| Member | Value | Description |
|---|---|---|
USER | 'user' | The user's own code. |
SETUP | 'setup' | The install and build commands that prepare the run. |
RUNNER | 'runner' | The platform's bootstrap around the user's code. |
UNKNOWN | 'unknown' | A source this SDK version does not know. |
LogStage
Which stage of the run a log line belongs to.
Members
| Member | Value | Description |
|---|---|---|
BUILD | 'build' | Preparing the environment the code runs in. |
RUN | 'run' | Executing the code. |
UNKNOWN | 'unknown' | A stage this SDK version does not know. |