Errors and transfers
Error envelope
Section titled “Error envelope”Requests fail with a JSON-RPC 2.0 error response. message is a short category label; inspect code and structured data for machine behavior. Do not parse Provider SDK text from the message.
{ "jsonrpc": "2.0", "id": 7, "error": { "code": -32602, "message": "Invalid params", "data": { "kind": "providerNotFound", "method": "bucket/list", "providerId": "missing" } }}| Code | Name | Meaning |
|---|---|---|
-32700 |
Parse error | The body was not valid JSON. |
-32600 |
Invalid Request | The JSON-RPC envelope or connection lifecycle was invalid. |
-32601 |
Method not found | The method is not registered in this revision. |
-32602 |
Invalid params | Parameters, cursors, identifiers, or a requested operation were invalid. |
-32603 |
Internal error | The server could not safely classify or serialize an internal failure. |
-32001 |
Overloaded | A bounded server resource is full; the client may retry later. |
-32002 |
S3 Provider error | The Provider rejected, failed, or returned an invalid response. |
-32003 |
Forbidden | The authenticated Principal is not authorized for the resource and action. |
-32004 |
Conflict | The requested operation conflicts with existing Provider state. |
Parse errors and requests whose IDs cannot be recovered use "id": null. Notifications never receive errors.
S3 Provider errors carry data.kind. providerRequestFailed is a failure. unsupportedOperation means the Provider does not implement the S3 operation at all — Garage and Cloudflare R2 answer every Bucket-policy method this way — so clients should degrade the feature rather than report the Provider as broken.
Bounded Object methods
Section titled “Bounded Object methods”object/get, object/version/get, object/put, and preview operations can carry bounded Object data through JSON-RPC. The server rejects bodies beyond server.max_object_body_bytes; the default is 16 MiB. These methods are useful for previews and intentionally small content, not general file transfer.
Object copies
Section titled “Object copies”object/copy writes the current source Object to any Bucket of any Provider in the Workspace and leaves the source in place; servers that support it report objectCopy: true in their initialize capabilities. Within one Provider the Provider performs the copy and the call fails with objectAlreadyExists when the destination key exists. Across Providers the server streams the body from the source to the destination inside the one call, so it can run for as long as the transfer takes and it replaces an existing destination — check the destination first, as before an upload. Both paths share the 5 GiB single-PUT ceiling. A source Provider that streams without a Content-Length cannot be relayed and fails with unknownContentLength.
{ "jsonrpc": "2.0", "id": 9, "method": "object/copy", "params": { "source": { "providerId": "aws", "bucketName": "photos", "key": "2026/summer.jpg" }, "destination": { "providerId": "r2", "bucketName": "backups", "key": "photos/2026/summer.jpg" } }}Streaming transfer tickets
Section titled “Streaming transfer tickets”Call object/transfer/create over the authenticated RPC channel, then redeem its relative same-origin URL over plain HTTP.
Download ticket request:
{ "jsonrpc": "2.0", "id": 10, "method": "object/transfer/create", "params": { "providerId": "garage", "bucketName": "media", "key": "video.mp4", "direction": "download" }}Upload requests use "direction": "upload", require the exact contentLength, and may provide contentType. Downloads may select versionId; uploads may not.
{ "jsonrpc": "2.0", "id": 10, "result": { "url": "/transfers/REDACTED", "expiresInSeconds": 120 }}Tickets have intentionally narrow semantics:
- They authorize exactly one direction, Provider, Bucket, and Object key.
- They are single-use and are consumed when redemption begins, even if the transfer later fails.
- An unused ticket expires after 120 seconds.
- Download URLs use
GET; upload URLs usePUTwith the exact declared content length. - When authentication is enabled, the redemption request’s origin must match
auth.public_origin. - Ticket URLs are credentials. Do not log, persist, preflight, retry, or share them.
After interruption or any failed redemption, mint a new ticket. Do not retry the old URL.