List Job Run Container Logs
Read a Job Run’s saved container output (stdout) and error output (stderr) as lines. Get the run’s UUID from GET /v1/job-runs.
Read logs
- Call with no parameters to read from the first line, oldest first. Each page holds at most
max_bytesof text (default 64 KiB). - While
has_moreis true, call again withcursorset to the returnednext_cursor. - To follow a running container, keep calling with the latest
next_cursor.next_cursoris never null; when you are caught up, the page is empty until new output arrives. - Stop when
completeis true.
Use tail=N for the last N lines, and since_ms / until_ms to limit lines by time. The cursor remembers these filters, so send them only on the first request.
Load earlier
Start with tail=N, then pass prev_cursor unchanged as cursor to load an adjacent earlier page. Optional tail controls backward page size (default 100). next_cursor always reads forward, including on a backward response. prev_cursor_status is available, start, or unsupported_boundary. A null prev_cursor at unsupported_boundary means forced partial-line boundaries cannot safely be reconstructed; it does not mean history started there. On backward requests, has_more refers to backward scan work. A bounded filtered scan may return an empty page with a new prev_cursor; continue with it. All pages remain in forward emission order. Backward pages keep complete=false; follow next_cursor to determine forward completion.
Response
Each line has timestamp_ms, stream (stdout or stderr) and message. Lines are returned exactly once, in the order they were saved. A line still being written (no newline yet) is returned once it ends, once it exceeds 16 KiB, or when the run ends. run_status is the run’s status, so you can tell when the container has started or finished. complete turns true once the run has ended and you have read to the end of its output. It turns true no sooner than 15 seconds after the run ends, and 60 seconds when the server cannot confirm that nothing is still in transit. Treat it as best effort: output delayed in transit past these checks can still arrive afterwards.
Errors
A 400 response carries error.code: cursor_invalid (the cursor is malformed or belongs to another run) or parameters_conflict (time filters sent with a cursor, or tail sent with a forward cursor). cursor_expired is reserved. cursor_reset_required means a bounded tail scan cannot reconstruct a partial line safely; restart without tail or cursor. A 503 with log_history_not_ready means the run’s saved output is still being indexed; retry after Retry-After seconds.
Access
Sign requests with your API key and HMAC headers. You need job_runs.read.own and must be the job’s creator or the assigned node’s operator. Accounts with job_runs.read.all can read any run.
Polling
This route uses the POLLING rate limit. Poll no more than once per second per run. A 429 response carries Retry-After with the seconds to wait.
Path Parameters
Query Parameters
Either next_cursor or prev_cursor, copied unchanged. It carries position and time filters. Only backward cursors accept tail; neither accepts since_ms or until_ms.
1Maximum UTF-8 bytes of message text per page (1–1,048,576; default 65,536). A page ends at a whole line; a single line longer than the cap is returned on its own.
1 <= x <= 1048576Return only lines with timestamp_ms at or after this Unix time in milliseconds.
x >= 0Return the last N lines (1–10,000), oldest first, within max_bytes. With a backward cursor, select up to N earlier lines (default 100). next_cursor continues forward.
1 <= x <= 10000Return only lines with timestamp_ms before this Unix time in milliseconds.
x >= 0Response
A page of saved container output lines, with a cursor to continue.
True when the run has ended and this response reaches the end of its output. tail, since_ms and until_ms do not change this: it describes the whole output, not the filtered lines. Once true, no later request returns more lines; stop polling. It turns true no sooner than 15 seconds after the run ends, and 60 seconds after when the server cannot confirm that no output is still in transit. These checks are best effort: output delayed in transit past them (for example, a large burst at the end of the run, or a queue backlog longer than 10 minutes) can still arrive after complete is true.
More scan work remains in the requested direction. Follow next_cursor for forward reads or prev_cursor for backward reads, including on empty filtered pages.
Lines oldest first. Empty when there is nothing new.
Pass this value unchanged as cursor to continue after the last line returned. Never null: when you are caught up, calling again with it returns new lines or an empty page.
1Pass unchanged as cursor to load the adjacent earlier page. Null at history start or an unsupported partial boundary.
1Explains whether earlier history is readable. unsupported_boundary is not the start of history.
available, start, unsupported_boundary The run’s status when this page was read, so you can tell a running container from a finished one without another request.
ASSIGNED, PREPARING, RUNNING, COMPLETED, CANCELLING, CANCELLED, FAILING, FAILED