openai/openai-python · error · ValueError
Expected a non-empty value for `run_id` but received {run_id
Error message
Expected a non-empty value for `run_id` but received {run_id!r} What it means
`steps.retrieve` validates `run_id` (second check) and raises this ValueError when it is falsy, because the run ID is required in the step retrieval path. The check happens before any network activity.
Source
Thrown at src/openai/resources/beta/threads/runs/steps.py:86
supported value is `step_details.tool_calls[*].file_search.results[*].content`
to fetch the file search result content.
See the
[file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings)
for more information.
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
"""
if not thread_id:
raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}")
if not run_id:
raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}")
if not step_id:
raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})}
return self._get(
path_template(
"/threads/{thread_id}/runs/{run_id}/steps/{step_id}",
thread_id=thread_id,
run_id=run_id,
step_id=step_id,
),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform({"include": include}, step_retrieve_params.StepRetrieveParams),
security={"bearer_auth": True},
),View on GitHub (pinned to 9917c6e28e)
Solutions
- Persist the run ID with every step ID you intend to fetch later
- Validate `run_id` before the call
- Avoid reusing variable names across loop iterations when building SDK calls
Example fix
# before step = client.beta.threads.runs.steps.retrieve(thread_id=thread_id, run_id=last_run, step_id="step_abc") # last_run overwritten to None # after run_id_to_use = run.id step = client.beta.threads.runs.steps.retrieve(thread_id=thread_id, run_id=run_id_to_use, step_id="step_abc")
Defensive patterns
Strategy: validation
Validate before calling
if not run_id:
raise ValueError("run_id required to retrieve a run step")
step = client.beta.threads.runs.steps.retrieve(thread_id=thread_id, run_id=run_id, step_id=step_id) Type guard
def is_valid_run_id(value: object) -> TypeGuard[str]:
return isinstance(value, str) and value.startswith("run_") Try / catch
try:
step = client.beta.threads.runs.steps.retrieve(thread_id=thread_id, run_id=run_id, step_id=step_id)
except ValueError as e:
if "run_id" in str(e):
logger.warning("step lookup skipped: run id missing")
else:
raise Prevention
- Avoid variable shadowing of run objects in loops
- Persist run IDs alongside step IDs
- Validate references loaded from external stores
When it happens
Trigger: Retrieving a run step with `run_id=None` or `""` — commonly when only the step ID was persisted, or the run variable was overwritten in a loop.
Common situations: Crawling steps from logs where only step IDs were recorded, or variable shadowing (`run` reused for iterations) leaving the wrong value in scope.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Expected a non-empty value for `thread_id` but received {thr
- Expected a non-empty value for `step_id` but received {step_
- Pagination is only supported with mappings
- No next page expected; please check `.has_next_page()` befor
- max_retries cannot be None. If you want to disable retries,
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/21cb88e5e6edeff4.
Report an issue: GitHub.