{"record":{"id":"c0c381d19b02ecc8","repo":"paperclipai/paperclip","slug":"request-failed-with-status-response-status","errorCode":null,"errorMessage":"Request failed with status ${response.status}","messagePattern":"Request failed with status (.+?)","errorType":"exception","errorClass":"ApiRequestError","httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/asset.ts","lineNumber":130,"sourceCode":"async function downloadAsset(apiBase: string, apiKey: string | undefined, assetId: string): Promise<Buffer> {\n  const response = await fetch(buildApiUrl(apiBase, apiPath`/api/assets/${assetId}/content`), {\n    headers: apiKey ? { authorization: `Bearer ${apiKey}` } : undefined,\n  });\n  if (!response.ok) {\n    await parseFetchResponse(response);\n  }\n  return Buffer.from(await response.arrayBuffer());\n}\n\nasync function parseFetchResponse(response: Response): Promise<unknown> {\n  const text = await response.text();\n  const parsed = text.trim() ? safeJson(text) : null;\n  if (!response.ok) {\n    const message =\n      typeof parsed === \"object\" && parsed !== null && \"error\" in parsed && typeof parsed.error === \"string\"\n        ? parsed.error\n        : `Request failed with status ${response.status}`;\n    throw new ApiRequestError(response.status, message, undefined, parsed);\n  }\n  return parsed;\n}\n\nfunction buildApiUrl(apiBase: string, path: string): string {\n  const url = new URL(apiBase);\n  url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}${path.startsWith(\"/\") ? path : `/${path}`}`;\n  return url.toString();\n}\n\nfunction safeJson(text: string): unknown {\n  try {\n    return JSON.parse(text);\n  } catch {\n    return text;\n  }\n}\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/client/asset.ts#L112-L148","documentation":"Fallback thrown by parseFetchResponse() in the asset command when response.ok is false AND the parsed body has no string `error` field. Unlike [0] (a plain Error), this is wrapped into an ApiRequestError(response.status, message, ...) so callers can branch on .status. Used by asset upload/download paths that go through parseFetchResponse rather than the PaperclipApiClient.","triggerScenarios":"Asset upload returns 4xx/5xx (e.g. 413 payload too large, 415 unsupported media type, 401 unauthenticated, 403 forbidden, 404 unknown asset on download, 500) and the body is empty or lacks `{ error: string }`. Also if the server's asset route is fronted by a proxy that emits plain status pages.","commonSituations":"Uploading a file larger than the server/proxy limit. Wrong/missing API key (401). Asset namespace/alt strings rejected by validation. Downloading an asset id that does not exist. Reverse proxy returning 413/502 with an HTML body.","solutions":["If 401/403: supply --api-key or run `paperclipai login`.","If 413: shrink the file or raise the server/proxy body-size cap.","If 404 on download: verify the asset id and company scope.","If the status is 5xx: retry once the server is healthy; check server logs.","If the body is HTML (proxy page), bypass the proxy or fix its error response format."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nfunction preflightAsset(file: string, maxBytes = 50 * 1024 * 1024) {\n  const st = fs.statSync(file);\n  if (!st.isFile()) throw new Error(`${file} is not a regular file`);\n  if (st.size > maxBytes) throw new Error(`${file} is ${st.size} bytes (> ${maxBytes}); will likely 413`);\n}","typeGuard":"function isApiErrorBody(v: unknown): v is { error: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).error === 'string';\n}","tryCatchPattern":"try { await uploadAsset(...); }\ncatch (err) {\n  if (err instanceof ApiRequestError) {\n    if (err.status === 401 || err.status === 403) console.error('Auth failed; run paperclipai login or pass --api-key.');\n    else if (err.status === 413) console.error('Asset too large; raise the server/proxy body limit or shrink the file.');\n    else console.error(`Asset HTTP ${err.status}: ${err.message}`);\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Pre-flight check file size against the server's body limit.","Ensure authentication (--api-key or board login) before upload.","Use a supported MIME (see cli inferContentTypeFromPath and server allowlist).","Avoid proxies that rewrite errors to HTML; the fallback message is least informative in that case."],"tags":["network","cli","asset","http-status","api-error"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}