Skip to content

v0.4.0

Choose a tag to compare

@SystemSculpt SystemSculpt released this 28 Jul 18:40
· 11 commits to main since this release
7675a58

⚠️ Behavior change — read before upgrading

Failed sandbox update_* and delete calls now raise SandboxAPIError instead of silently returning a malformed object.

Every generated control-plane API function returns Union[Error, T] | None, so an error status is a return value, not an exception. SandboxInstance.update_metadata, update_ttl, update_lifecycle, update_network and delete passed that response straight into cls(response), which does not type-check. A 403/404/500 therefore produced an instance wrapping an Error.

If you ignored the return value — the common shape — a failed write looked like a success:

  • update_ttl returned normally and the TTL was never applied
  • delete returned normally and the sandbox stayed alive and kept billing

If you used the return value, you hit AttributeError: 'Error' object has no attribute 'metadata' far from the real cause.

What this means for you

you impact
Your calls succeed No change. Same objects, same types, same behavior.
Your calls have been failing silently You now get exceptions. You were already broken — the update never applied, the delete never happened.
You wrote a workaround checking isinstance(result.sandbox, Error) This breaks. The call now raises before returning, so your check never runs.

Most notably: delete() on an already-deleted sandbox now raises where it previously returned quietly. If you delete in a finally: or a cleanup path, wrap it:

try:
    await sandbox.delete()
except SandboxAPIError:
    pass  # already gone

Also: delete() on an empty response now raises SandboxAPIError rather than ValueError.

This brings Python in line with the TypeScript SDK, which has always used throwOnError: true on these calls, and with Go, which returns idiomatic (res, err). Python was the only SDK swallowing these errors.

Fixes

  • fix(sandbox): propagate control-plane errors from update_*/delete (#206, ENG-4244)

    • all four update_* helpers and delete, in both the async and sync (SyncSandboxInstance) trees
    • delete no longer raises a misleading ValueError("Sandbox X not found") for what may have been a 500
    • VolumeInstance.delete had the same gap and now raises on both Error and empty responses
    • Reported by Albert at EvenUp, who also identified the correct fix: routing through the existing _unwrap_response() helper.
  • fix(deps): cap mcp below 2.0.0 (#207, ENG-4250)

    • mcp 2.0.0 removed mcp.server.fastmcp, which blaxel.core.mcp.server subclasses, breaking every fresh install
    • migrating off that surface and lifting the cap is tracked in ENG-4255

Verification

  • Red/green: with the source fix reverted and only the new tests applied, 18 tests fail; with it restored, all pass
  • 423 unit tests passing; full integration suite green
  • One integration test was found to be passing for the wrong reason — it built a lifecycle with a duplicate ttl-idle policy that the control plane rejects with a 400, and the swallowed error meant the update never applied. Fixed.

Full diff: v0.3.5...v0.4.0