fix(openai): preserve non-not-found provider errors - #65
Draft
isaacbmiller wants to merge 7 commits into
Draft
Conversation
Updated Deno installation instructions for MacOS and added information about Deno's handling of package.json files. Signed-off-by: Michal Migurski <mike@cmpnd.ai>
…ram found (stanfordnlp#9705) * fix: correct demo index assignment in MIPROv2 optimizer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: raise ValueError instead of UnboundLocalError when no valid program found get_program_with_highest_avg_score would fall through to a return that references undefined variables when sorted_results was empty. Now raises a clear ValueError with context. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…als (stanfordnlp#9991) _serialize_value used str() for floats, so float('inf') / float('-inf') / float('nan') became the bare words "inf" / "-inf" / "nan" and were injected into sandbox code as `x = inf`, raising NameError. This breaks direct PythonInterpreter use and silently degrades RLM when a float input field carries a non-finite value (the error is caught and fed back to the model, so the input becomes inaccessible). Wrap non-finite floats as float('...') so they evaluate correctly in the sandbox. Normal floats and ints are unchanged. Co-authored-by: Vinay152003 <vinay152003@users.noreply.github.com>
Issue / repro: DSPy declares openai>=0.28.1 even though shipped runtime paths use the v1 OpenAI client, fine_tuning.jobs and files resources, typed API errors, and Responses reasoning summaries. OpenAI 0.28.1 provides none of those v1 entry points. Root cause: The 0.x-compatible lower bound survived after DSPy adopted v1-only fine-tuning and Responses APIs. The lock hid the mismatch by resolving OpenAI 1.75 or 1.88 in development and CI. Why this proves the root cause: An isolated 0.28.1 probe lacks OpenAI, NotFoundError, fine_tuning, and files. The lowest valid LiteLLM graph resolves OpenAI 1.66.1, which has the v1 APIs but lacks the corrected ResponseReasoningItem schema. The same graph at 1.66.2 verifies the runtime resources, error classes, and a reasoning summary. Upstream released 1.66.2 only 75 minutes after 1.66.1 specifically to correct the Responses reasoning output type. Why this boundary and fix are minimal: The change updates only the source requirement and its mirrored lock metadata. It does not change an OpenAI package version, hash, transitive dependency, runtime branch, or compatibility fallback. The existing 1.75 and 1.88 lock selections remain intact. Context: This is a declared-contract correction, not the separate OpenAI 2.x Dependabot upgrade. Versions pinned at or below 1.66.1 will now fail resolution intentionally because they do not cover DSPy's complete shipped OpenAI surface. Actual fix: Raise the declared and locked project requirement from openai>=0.28.1 to openai>=1.66.2. Verification: Exact minimum probe: LiteLLM 1.64.1 plus OpenAI 1.66.2 passed resource, error, and Responses reasoning checks. Below-floor control: OpenAI 1.66.1 lacked ResponseReasoningItem as expected. uv sync --all-extras --frozen uv run --frozen pytest --deno -q tests/clients uv run --frozen pytest --deno -q tests/adapters/test_json_adapter.py -k responses uv build --out-dir /tmp/dspy-openai-floor-dist uv run --frozen pre-commit run --all-files Wheel metadata: Requires-Dist: openai>=1.66.2 Scope audit: A uv lock dry run requests only the pre-existing unrelated DSPy root-version update from 3.2.1 to 3.3.0b1. That line is intentionally excluded from this commit.
Issue / repro: OpenAI existence probes returned False for authentication and other retrieval failures, making them indistinguishable from missing jobs or files. Current callers can then skip remote cancellation or deletion, clear local provider state after a failed lookup, or replace the original provider error with a misleading absence assertion. Root cause: Both helpers caught Exception around the SDK retrieve call. Only openai.NotFoundError proves remote absence; a None identifier is already known locally to be absent. Why this proves the root cause: The parameterized regression covers jobs and files across success, 404, 401, and None. Applied to the parent tree, it fails specifically because the 401 is swallowed. It passes after the catch is narrowed. Why this boundary and fix are minimal: The OpenAI SDK owns HTTP error classification, so the provider translates only NotFoundError into False. The fix adds no retry or compatibility path: it short-circuits None, catches one expected exception, and leaves every other provider failure untouched. Context: These helpers sit at the OpenAI SDK boundary and are used by cancellation and training-status paths. The provider should preserve SDK errors unless the SDK has specifically classified the resource as missing. Actual fix: Return False without an SDK call for None IDs, return False for openai.NotFoundError, return True after successful retrieval, and propagate all other SDK exceptions. Verification: uv run --frozen pytest --deno -q tests/clients/test_openai_provider.py uv run --frozen pytest --deno -q tests/clients uv run --frozen ruff check dspy/clients/openai.py tests/clients/test_openai_provider.py
isaacbmiller
force-pushed
the
agent/openai-existence-errors
branch
from
July 13, 2026 14:27
48c51be to
917a262
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
None) as absent without calling OpenAI.openai.NotFoundError) as remote absence.Review dossier
1. Issue / repro
Before this PR, both existence probes used this shape:
That makes a 401, timeout, rate limit, or server error indistinguishable from a 404.
This matters because the result controls whether cancellation and deletion happen:
If the lookup fails with a 401, the old helper returns
False: remote cancel/delete is skipped, and the file path still clears its local provider ID. The same false negative in training-status lookup replaces the provider error with a misleading assertion:2. Why this is the root cause
The broad
except Exceptionconflates two different outcomes:The OpenAI SDK already classifies HTTP failures.
openai.NotFoundErroris the precise boundary for the first outcome.3. How the regression proves it
One parametrized test exercises both helpers across the complete decision table:
TrueNotFoundError(404)FalseAuthenticationError(401)NoneIDFalse, no SDK callThe key negative case is explicit:
Applied to the parent tree, this fails because the broad catch swallows the 401. It passes after narrowing the catch.
4. Why this is concise
The production change is limited to the two symmetric existence probes:
Noneguard;The two intentional fallback paths remain: a missing local ID and a provider-confirmed 404.
5. Context needed to validate it
These helpers are the OpenAI SDK boundary used by cancellation and training-status paths. The provider already uses the SDK’s v1 resource APIs, so it should rely on the SDK’s error classification instead of inferring absence from arbitrary failures.
6. What the fix does
The complete job boundary is now:
does_file_existapplies the same boundary toopenai.files.retrieve. Successful retrieval returnsTrue;NoneandNotFoundErrorreturnFalse; every other SDK exception retains its original type and context.Verification
AuthenticationErrordoes not propagate.uv run --frozen pytest --deno -q tests/clients/test_openai_provider.py— 2 passed.uv run --frozen pytest --deno -q tests/clients— 135 passed, 21 skipped.uv run --frozen ruff check dspy/clients/openai.py tests/clients/test_openai_provider.py— passed.git diff --check cmpnd/main..HEAD— clean.Scope
One commit, two files: the provider boundary and its focused regression test.