feat(jql): explain the opaque 404 from the public JQL API - #767
Open
JJwilkin wants to merge 1 commit into
Open
Conversation
A valid JQL query against an organization without the `public_jql` feature flag raised a bare `JudgmentAPIError: 404: Resource not found`, which gave callers nothing to act on. The server answers 404 identically whether the feature is disabled or the project does not exist, so the SDK cannot positively identify either cause. Raise a new `JudgmentJQLUnavailableError` that names both and points at the fix. Because the organization-level gate runs before the project lookup server-side, a `Project not found` detail can only come from an enabled organization, so use it to sharpen the message and fall back to naming both causes otherwise. The mapping lives in `_run_jql` rather than `map_judgment_api_error` because that mapper is shared with datasets and offline tests, where a 404 is unrelated to JQL. The new error subclasses `JudgmentAPIError`, so existing `except JudgmentAPIError` callers are unaffected. Co-Authored-By: Claude <noreply@anthropic.com>
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
A valid JQL query from an organization without the
public_jqlfeature flag raised a bareJudgmentAPIError: 404: Resource not found, giving callers nothing to act on.JudgmentJQLUnavailableError(subclass ofJudgmentAPIError) for 404s on JQL routes, exported fromjudgeval.exceptions_run_jql— the single choke point coveringquery,present, anddiscoverProject '<name>' was not found for this organization.when the server detail isProject not foundBefore
After
Why the message names two causes
judgeval-serverthrowsNotFoundError('Resource not found')when thepublic_jqlflag is off, which is byte-identical to the 404 for a missing project, and the published OpenAPI documents 404 as "Project or public JQL endpoint not found". The SDK therefore cannot positively identify the disabled flag, and claiming it could would mislead the much more common case of a typo'd project name. Naming both causes plus the next step is the honest maximum available client-side.One string does discriminate: the org-level gate runs before the project lookup server-side, so a
Project not founddetail can only come from an already-enabled org. That is used to sharpen the message, with a comment marking the coupling and a safe fallback if the server text ever changes.Design notes
_run_jql, not inmap_judgment_api_error's status table — that mapper is shared withdatasets/andoffline_tests/, where a 404 has nothing to do with JQL.JudgmentAPIError, so existingexcept JudgmentAPIErrorcallers are unaffected (asserted in a test).JudgmentAPIError, so the exact-vars()assertions intest_jql.pystill hold._generated_contract.py/_generated_transport.pyare untouched.Follow-up (not in this PR)
Worth deciding separately: have
judgeval-serversend a distinguishableerrorcode for the flag-off case, letting both SDKs state the cause outright instead of inferring it. If the current ambiguity is intentional non-disclosure, leave it as is.✅ Checklist
Testing
uv run pytest src/tests→ 643 passeduv run mypy ./src/judgeval/→ clean (196 files)uv run ruff check ./ruff format --check .→ cleanexcept JudgmentAPIErrorback-compat, and non-JQL 404 left unmapped🤖 Generated with Claude Code