{"record":{"id":"c2121e0cbcd0682f","repo":"can1357/oh-my-pi","slug":"destination-upload-failed-with-http-status","errorCode":null,"errorMessage":"${destination} upload failed with HTTP ${status}","messagePattern":"(.+?) upload failed with HTTP (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploader-runtime.ts","lineNumber":121,"sourceCode":"\n/** Build a native multipart form containing string fields and the uploaded file. */\nexport function multipartFile(\n\trequest: BlobUploadRequest,\n\tfieldName = \"file\",\n\tfields: Readonly<Record<string, string>> = {},\n): FormData {\n\tconst form = new FormData();\n\tfor (const key in fields) form.append(key, fields[key]);\n\tconst file = new File([request.bytes], fileNameFor(request), { type: request.mimeType });\n\tform.append(fieldName, file);\n\treturn form;\n}\n\n/** Return a successful response or throw a secret-safe HTTP status error. */\nexport async function expectOk(response: Response, destination: BlobDestinationId | string): Promise<Response> {\n\tif (!response.ok) {\n\t\tconst status = response.statusText ? `${response.status} ${response.statusText}` : String(response.status);\n\t\tthrow new Error(`${destination} upload failed with HTTP ${status}`);\n\t}\n\treturn response;\n}\n\n/** Construct a durable publication while preserving all upstream metadata. */\nexport function publication(\n\tdestination: BlobDestinationId,\n\trequest: BlobUploadRequest,\n\turl: string,\n\textras: PublicationExtras = {},\n): BlobPublication {\n\treturn {\n\t\turl,\n\t\tdestination,\n\t\tbytes: request.bytes.byteLength,\n\t\t...(extras.expiresAt === undefined ? {} : { expiresAt: extras.expiresAt }),\n\t\t...(extras.delete === undefined ? {} : { delete: extras.delete }),\n\t\t...(extras.remoteId === undefined ? {} : { remoteId: extras.remoteId }),","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploader-runtime.ts#L103-L139","documentation":"expectOk checks an HTTP response and throws a secret-safe error containing only the destination name and status code when the response is not ok. Response bodies are intentionally excluded because they could echo back credentials, file contents, or signed URLs. Any non-2xx from an upload/list/session/permission endpoint surfaces as this error.","triggerScenarios":"Any uploader call routed through expectOk — upload, uploadedResponse, listResponse, sessionResponse, permissionResponse — where the remote returns HTTP 4xx or 5xx (401 unauthorized, 403 forbidden, 404, 413 payload too large, 429 rate limit, 5xx outage).","commonSituations":"Expired or revoked auth token, uploading a file larger than the host's limit, hitting rate limits on public file hosts, destination service downtime, or wrong base URL in config.","solutions":["Read the status in the error message: 401/403 → fix or refresh the credential; 413 → shrink the file; 429 → back off and retry.","Verify the configured base URL/endpoint for the destination is correct.","Test the endpoint manually (curl) with the same request to see whether it's auth, size, or availability.","Check the destination host's status page if the status is 5xx."],"exampleFix":"// before: retry blindly on any failure\nawait uploader.upload(req);\n// after: inspect status and react\ntry {\n  await uploader.upload(req);\n} catch (err) {\n  if (/HTTP 429/.test(String(err))) await Bun.sleep(60_000);\n  else throw err;\n}","handlingStrategy":"retry","validationCode":"// precondition check: config sanity before upload\nif (!config.credentials?.apiKey) throw new Error(\"upload will 401: apiKey not configured\");","typeGuard":null,"tryCatchPattern":"try {\n  await expectOk(res, destination);\n} catch (err) {\n  const m = /HTTP (\\d{3})/.exec(String(err));\n  const status = m ? Number(m[1]) : 0;\n  if (status === 429 || status >= 500) await retryWithBackoff();\n  else if (status === 401 || status === 403) refreshCredential();\n  else throw err;\n}","preventionTips":["Check file size against the destination host's documented limit before uploading.","Rotate credentials proactively and verify them with a lightweight authed request first.","Implement exponential backoff for 429/5xx and surface 4xx to the user immediately.","Remember the error is secret-safe: to debug details, reproduce the request manually with curl."],"tags":["network","http","upload"],"backgroundTag":"http-upload-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}