> ## Documentation Index
>
> Fetch the complete documentation index at: https://lithi.ai/llms.txt
>
> Use this file to discover all available pages before exploring further.

---
title: Read partial results with cursors
description: >-
  Page through a running job with opaque stable cursors, read per-item outcomes
  as you go, and tell an immutable available part apart from a terminal bundle.
route: /docs/compute/results/partials-and-cursors
page_id: docs-compute-results-partials-and-cursors
page_type: howTo
content_layer: guided documentation
surface_profile: guided_docs
audience: Integrators reading results while a job is still running
voice: D
reader_question: How do I read results while a job is still running without misreading them?
primary_action: Confirm the manifest before you treat a run as finished
source_locale: en-US
source_status: APPROVED
source_version: docs-compute-results-partials-and-cursors-en-us-2026-09-05-v1
last_updated: '2026-09-05'
robots: index
claim_registry_pinned: true
claim_registry_resync: "npm run governed:tsx -- scripts/build-compute-public-claim-registry.ts --write"
---

## Before you start paging

You need a job that has been admitted and is producing output. A job in `RUNNING` may already have readable parts; a job in `PARTIAL` has finished with some work incomplete.

You also need somewhere to hold a cursor between calls. Cursors are how you resume without rereading, and losing one costs you a full re-page.

## Take the cursor from the response, not from your own count

Each result page returns a cursor. Treat it as opaque: it is a token to hand back, not a number to parse, compare, increment or store as an offset.

Cursors are stable. Handing the same cursor back returns the same position, so a retry after a dropped connection resumes rather than duplicates.

Never build your own cursor from a row count or a timestamp. A cursor you constructed is not a cursor Compute issued, and it will not resume where you think it does.

## Read the per-item outcome on every row

Each row carries its own outcome in `lithi_status`, with `lithi_error_code` set when the item did not succeed. Read them per item, not per page.

A page can contain accepted rows, failed rows and abstentions together. Treating a returned page as uniformly successful is the most common way partial reads go wrong.

## Available parts are immutable, and not terminal

A part that is available to you will not change afterwards. What you read stays read, and re-reading returns the same bytes.

Immutable is not the same as complete. Available parts tell you what has landed so far; they say nothing about what is still to come, or whether the run will succeed.

`result-manifest.json` is written last and is the only complete-bundle marker. Until it is present, you are looking at work in progress, whatever the part files contain.

## Never infer missing work from ordering

Parts are not ordered against each other, and item order inside a part is not a processing order. A gap in your source ordering is not a skipped item.

Reconcile by item identifier instead. Join each result row back to your source row through the identifier your input declared, then compare sets rather than sequences.

When the run is terminal, reconcile against the manifest counts, which cover accepted rows, failures, abstentions and disagreements together.

## What success looks like

You hold a stored cursor, a set of item identifiers you have already read, and a per-item outcome for each. When the manifest appears, your counts and its counts agree.

If they do not agree, re-page from the last cursor you stored rather than from the beginning. A duplicate read is harmless; a guessed offset is not.

## If paging stops partway

A dropped connection is a resume, not a rerun. Hand back your stored cursor and continue — resubmitting the job risks a second charge for work you already have.

If the cursor is rejected, the response carries a typed state and a next action. Follow that next action; do not fall back to reading from the start of a running job.

If the job itself ends `PARTIAL`, read the exceptions before the accepted rows. Start with [failures, abstentions and disagreements](/docs/compute/results/failures-abstentions-disagreements), then confirm the bundle against [the result bundle layout](/docs/compute/results/bundle-layout).
