Skip to content

Errors and transfers

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.

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/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" }
}
}

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 use PUT with 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.