Skip to content

feat: add BlaxelAPIError with auto-throw on 4xx/5xx responses#295

Open
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1777574774-blaxel-api-error
Open

feat: add BlaxelAPIError with auto-throw on 4xx/5xx responses#295
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1777574774-blaxel-api-error

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 30, 2026

Summary

The control plane API client (generated @hey-api/client-fetch) does not automatically throw on 4xx/5xx responses — it returns typed error objects or undefined. The Go SDK auto-raises on all 4xx/5xx (sdk-go internal/requestconfig/requestconfig.go:526). This PR brings the TypeScript SDK to parity.

Changes

  1. BlaxelAPIError (@blaxel/core/src/client/errors.ts) — new error class with statusCode, errorBody, response, optional errorCode, and a code property that mirrors the API body's code field (or falls back to the HTTP status). The code property ensures backward compatibility with existing catch blocks that check e.code.

  2. apiErrorInterceptor (@blaxel/core/src/client/responseInterceptor.ts) — response interceptor that runs after authenticationErrorInterceptor, checks response.status >= 400, parses the JSON body, and throws BlaxelAPIError. Gated by settings.throwOnError.

  3. throwOnError config option (@blaxel/core/src/common/settings.ts) — added to the Config type and Settings class. Defaults to true (auto-raise). Users can opt out with initialize({ throwOnError: false }).

  4. ResponseError extends BlaxelAPIError (@blaxel/core/src/sandbox/action.ts) — sandbox operations now throw a ResponseError that is an instanceof BlaxelAPIError, maintaining backward compatibility for code that catches ResponseError while also being catchable as BlaxelAPIError.

  5. waitForDeletion updated (@blaxel/core/src/sandbox/preview.ts) — updated to use try/catch with BlaxelAPIError instead of manually checking response.status, since the interceptor now throws before the caller can inspect the response.

  6. Public exportBlaxelAPIError is exported from @blaxel/core via client/client.ts.

  7. README — added "Error handling" section with try/catch examples and opt-out instructions.

Review & Testing Checklist for Human

  • Breaking change assessment: With throwOnError: true by default, any existing code that calls control-plane SDK functions (e.g. listAgents, getAgent) and inspects { data, error } tuples without try/catch will now get uncaught exceptions. Verify this is the desired migration path.
  • code property semantics: BlaxelAPIError.code prefers the code field from the JSON body (e.g. 409 or "SANDBOX_ALREADY_EXISTS"), falling back to statusCode. Verify this matches existing catch block assumptions.
  • Opt-out test: Call initialize({ throwOnError: false }) and verify control-plane calls return { data, error } tuples without throwing.

Notes

  • The authenticationErrorInterceptor (which enriches 401/403 bodies with doc links) runs first, so BlaxelAPIError.errorBody for auth errors will include the documentation field.
  • All 11 environment compatibility checks pass. The single Integration Tests failure is an unrelated flaky latency benchmark ("declared vs undeclared port preview latency comparison" — expected 1 to be +0).
  • All previously failing integration tests (sandbox-crud, drives, interpreter, previews createIfNotExists/waitForDeletion) now pass after adding the .code property and updating waitForDeletion.

Link to Devin session: https://app.devin.ai/sessions/1a9828aa9ec040c99f724380cee61669
Requested by: @Joffref


Note

This PR adds a BlaxelAPIError class and an apiErrorInterceptor that auto-throws on HTTP 4xx/5xx responses, bringing the TypeScript SDK to parity with the Go SDK's behavior. It makes ResponseError extend BlaxelAPIError for a unified error hierarchy, adds a throwOnError opt-out config option, and updates waitForDeletion to use try/catch instead of inspecting response.status.

Written by Mendral for commit 925ff83.

- Create BlaxelAPIError class in @blaxel/core/src/client/errors.ts
- Add apiErrorInterceptor that throws BlaxelAPIError on HTTP 4xx/5xx,
  matching the Go SDK's auto-raise behaviour
- Add throwOnError config option (true by default, opt-out via false)
- Update ResponseError to extend BlaxelAPIError for consistency
- Export BlaxelAPIError from the package's public API
- Add Error handling section to README with usage examples

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Joffref and others added 2 commits April 30, 2026 19:00
…tch blocks

The SDK's createIfNotExists/get methods catch errors and check e.code
to distinguish expected 404/409 from unexpected errors. BlaxelAPIError
now exposes a .code property that reflects the code field from the API
JSON body (e.g. 409 or 'SANDBOX_ALREADY_EXISTS'), falling back to the
HTTP status code.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ng response.status

The response interceptor now throws BlaxelAPIError before the caller
can inspect response.status. Use try/catch with BlaxelAPIError code
check (matching the pattern used by createIfNotExists) instead.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
mendral-app[bot]

This comment was marked as outdated.

…etion

When settings.throwOnError is false, the apiErrorInterceptor skips and
hey-api/client-fetch throws the parsed JSON body directly (a plain
object with .code, not a BlaxelAPIError). Add a fallback check for
plain objects with code === 404 so waitForDeletion works regardless of
the throwOnError setting.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@mendral-app mendral-app Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The previous waitForDeletion bug is correctly fixed in commit 925ff83: the fallback "code" in e && e.code === 404 handles the hey-api plain-object throw when throwOnError: false. The rest of the PR is well-structured and the implementation is correct.

Tag @mendral-app with feedback or questions. View session

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.

1 participant