Skip to content

Fix null base_version_id, error messages, FileUpload(file_obj=...), 429 handling - #92

Open
jadenfix wants to merge 6 commits into
roe-ai:mainfrom
jadenfix:fix/response-handling
Open

jadenfix wants to merge 6 commits into
roe-ai:mainfrom
jadenfix:fix/response-handling

Conversation

@jadenfix

@jadenfix jadenfix commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

One commit per fix:

  • A null policy base_version_id came back as the all-zero UUID, so callers couldn't tell "no base version" from a real one. The generated PolicyVersion already types it None | UUID; it's now None.
  • RoeAPIException.message could be a list or dict. A list in detail/error/message is now joined with "; " (as list bodies already are), and other non-string values go through str().
  • FileUpload(file_obj=...) rejected every real file object. The field is typed typing.BinaryIO and pydantic checks it with isinstance, which open(..., "rb") and io.BytesIO both fail. Validation is skipped for that field; the annotation is unchanged.
  • FileUpload used pydantic's deprecated class-based Config, which warns on import. Now model_config = ConfigDict(arbitrary_types_allowed=True).
  • 429 had no exception type and retries ignored Retry-After. Adds RateLimitError(RoeAPIException) (existing except RoeAPIException still matches), and the transport now waits for an integer Retry-After on 429/503, capped at 60s.

Testing

Fixes #88.

Note: a Roe API key is required to test these changes end to end; the unit tests here run without one.

PolicyVersion.base_version_id is typed None | UUID, but the policy
version wrapper replaced a null value with the all-zero UUID before
parsing. Callers could not tell "no base version" apart from a real
one. The zero-UUID substitution dates from when the generated field was
non-nullable; now a null stays None (a missing key is still tolerated).

Tested: new test fails before (got UUID('00000000-...')) and passes
after; uv run pytest, ruff check, ruff format --check all pass.
translate_response took "detail", "error" or "message" from a JSON
error body as-is, so a body like {"detail": ["a", "b"]} or
{"error": {...}} produced an exception whose .message was a list or
dict, despite the str annotation. A list is now joined with "; " (as
list bodies already are) and any other non-string value is str()'d.

Tested: new parametrized test fails before (message was ['a', 'b'] /
{'code': 'bad'}) and passes after; uv run pytest, ruff check, ruff
format --check all pass.
FileUpload declared its Pydantic settings with the class-based
`class Config`, which Pydantic 2 deprecates and which emits a
PydanticDeprecatedSince20 warning every time roe.models.file is
imported. Switch to model_config = ConfigDict(...) with the same
setting (arbitrary_types_allowed=True).

Tested: new test importing roe.models.file under
-W error::DeprecationWarning fails before and passes after; the
pytest warning summary is now empty; uv run pytest, ruff check, ruff
format --check all pass.
file_obj is typed typing.BinaryIO, and with arbitrary_types_allowed
pydantic validates it with isinstance(). Real file objects (open(...,
"rb"), io.BytesIO) are not instances of typing.BinaryIO, so every
FileUpload(file_obj=...) raised ValidationError and the file-object path
was unusable. Keep the annotation but skip validation for this field.

Tested: new test in tests/unit/test_file_upload.py fails before
(ValidationError: Input should be an instance of BinaryIO), passes
after; full suite, ruff check and ruff format --check pass.
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] This PR appears safe to merge; no actionable issues were found.

Summary

This PR fixes three SDK edge cases and removes a deprecated Pydantic configuration.

  • Policy versions keep a missing base version as None.
  • API errors turn non-string details into readable messages.
  • FileUpload accepts real file objects for uploads.

jadenfix explicitly chose to skip validation of file_obj because the old check rejected real file objects.

Reviews (1) · Last reviewed commit: "Accept real file objects in FileUpload(f..." · Reviewed by Greptile

429 fell through to the base RoeAPIException, so callers couldn't catch
rate limiting by type. RateLimitError subclasses RoeAPIException, so
existing handlers still match. Part of roe-ai#88.
The transport retried rate-limited requests after 1-4s regardless of the
server's Retry-After. Wait for an integer Retry-After (capped at 60s)
when it exceeds the backoff; HTTP-date values keep the backoff. Part of roe-ai#88.
@jadenfix jadenfix changed the title Fix null base_version_id, non-string error messages and FileUpload(file_obj=...) Fix null base_version_id, error messages, FileUpload(file_obj=...), 429 handling Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

429 handling: Retry-After ignored, no RateLimitError

1 participant