Slow list_threads and read_thread calls on large LangSmith projects

Last updated: July 31, 2026

Symptom

On a large or long-running LangSmith project, calls to the v1 thread APIs in the Python SDK get slow or time out:

  • client.read_thread(thread_id=...) takes tens of seconds even for a thread with only a handful of runs.

  • client.list_threads(project_name=...) with a large limit (for example, several hundred) never finishes in a usable time.

  • list_threads without a start_time returns fewer threads than expected, or an empty list, on a project with plenty of older activity.

Cause

list_threads and read_thread in the v1 API are built on top of the general run-listing query path. They fetch full Run objects and group them by thread on the way out. There is no dedicated server-side thread index in v1, so the cost of a call scales with how many runs fall inside the time window you scan.

list_threads: silent 1-day default, expensive when widened. If you omit start_time, the SDK substitutes "now minus 1 day" before sending the request. This is documented but easy to miss. Two things go wrong from there:

  • If your project has activity older than a day and you didn't pass start_time, threads outside that 24-hour window are silently excluded. The response looks valid, just incomplete.

  • If you pass a far-past start_time (weeks or months) together with a large limit, the backend has to scan, group, sort, and marshal a very large number of runs in one synchronous call. That is where the timeouts come from.

read_thread: no default time bound at all. Unlike list_threads, read_thread does not apply a default start_time. With no time bound, it scans the entire project history to find runs matching the given thread_id. On a project with hundreds of thousands of traces, that is an unbounded scan, which is why even a thread with two or three runs can take a long time to return. It also returns full Run objects, so the response payload is heavy.

Resolution

The single most impactful change on the v1 API is to always pass a start_time, sized to the smallest window that covers the data you actually need.

list_threads: pass start_time explicitly.

import datetime

threads = client.list_threads(
    project_name="my-project",
    start_time=datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=7),
)

read_thread: narrow the underlying scan with a filter expression using LangSmith trace query syntax.

for run in client.read_thread(
    thread_id="<thread-id>",
    project_name="my-project",
    filter='gt(start_time, "2024-01-01T00:00:00Z")',
):
    ...

Two habits that keep v1 calls fast:

  • Keep the time window as narrow as the use case allows. For near-real-time work (for example, aggregating the current session), hours is usually enough.

  • Avoid pairing a large limit with a wide window. Paginate with smaller pages over smaller windows instead of asking for hundreds of threads in one call.

Upgrade path: v2 thread methods (Python SDK 0.10.0+)

The v2 methods were built to address these performance issues directly. They use a dedicated server-side threads index and return lightweight thread objects instead of full Run payloads.

v1

v2

client.list_threads()

client.threads.query()

client.read_thread()

client.threads.list_traces()

  • client.threads.query() uses min_start_time and max_start_time (both default to a 1-day window, with no silent over-scan) and cursor pagination with page_size from 1 to 100 (default 20).

  • client.threads.list_traces(thread_id, project_id) returns lightweight ThreadTrace objects with preview fields. A selects parameter lets you request only the fields you need.

The v2 thread methods on the Python Client are async-only: use await and async for. The v1 methods remain sync-only.

Watch for these parameter changes when migrating:

  • project_name is not accepted. Resolve to project_id first via client.read_project(project_name=...) and pass project_id.

  • Single start_time becomes an explicit min_start_time and max_start_time pair.

  • offset + limit becomes cursor + page_size.

References