{"record":{"id":"9b9358c96c12be86","repo":"jackwener/OpenCLI","slug":"no-signed-url-returned-for-attachment-id","errorCode":null,"errorMessage":"no signed url returned for attachment ${id}","messagePattern":"no signed url returned for attachment (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/slock/attachment-download.js","lineNumber":57,"sourceCode":"  columns: ['attachmentId', 'out', 'sizeBytes'],\n  func: async (page, kwargs) => {\n    const id = String(kwargs.attachmentId ?? '').trim();\n    if (!UUID_RE.test(id)) throw new ArgumentError(`attachmentId \"${id}\" is not a UUID`);\n    const out = path.resolve(String(kwargs.out ?? `./${id}.bin`));\n\n    // Step 1 — in-page, resolve the signed URL with the user's Slock session.\n    await page.goto(SLOCK_HOME_URL);\n    const snippet = buildFetchSnippet({\n      method: 'GET',\n      path: `/attachments/${encodeURIComponent(id)}/url`,\n      serverScoped: true,\n      serverIdOverride: kwargs.server,\n    });\n    const result = await page.evaluate(`(async () => { ${snippet} })()`);\n    const rows = dispatchEvaluateResult(result);\n    const data = Array.isArray(rows) ? rows[0] : rows;\n    const url = data?.url;\n    if (!url) throw new CommandExecutionError(`no signed url returned for attachment ${id}`);\n\n    // Step 2 — Node side, fetch the bytes from the signed CDN URL. No auth\n    // header (URL is pre-signed); no Origin (Node fetch has none) so CORS\n    // isn't in play.\n    let res;\n    try { res = await fetch(url); }\n    catch (e) { throw new CommandExecutionError(`network error fetching signed URL: ${e.message}`); }\n    if (!res.ok) {\n      throw new CommandExecutionError(`HTTP ${res.status} from signed CDN URL while downloading ${id}`);\n    }\n    const ab = await res.arrayBuffer();\n    fs.writeFileSync(out, Buffer.from(ab));\n    return [{ attachmentId: id, out, sizeBytes: ab.byteLength }];\n  },\n});\n","sourceCodeStart":39,"sourceCodeEnd":73,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/attachment-download.js#L39-L73","documentation":"A CommandExecutionError thrown after evaluating the in-page fetch snippet: the browser-context code ran but the returned data contained no url property, meaning no pre-signed download URL was obtained for the attachment. This indicates the signed-URL resolution step succeeded at the transport level but the server did not return a usable URL (auth/session issue, wrong attachment, or unexpected response shape).","triggerScenarios":"page.evaluate returned a result where data?.url is undefined — the in-page API call returned an error payload, an empty object, or a shape dispatchEvaluateResult maps to something without url, e.g. expired Slock session cookie, nonexistent attachmentId, or server-side denial.","commonSituations":"Slock session expired so the API returns an auth error object instead of a URL; the attachment was deleted or access-restricted; the server slug override (--server) points to an environment where the attachment doesn't exist; an API response schema change so the URL now lives under a different key.","solutions":["Re-authenticate / refresh the Slock browser session so the in-page fetch carries valid cookies","Verify the attachmentId exists and is accessible for the active or overridden server (--server)","Inspect the raw dispatchEvaluateResult payload (log `result`/`data`) to see the actual error the server returned","Update buildFetchSnippet if the API response schema changed and the URL is under a new key"],"exampleFix":"// before\nif (!url) throw new CommandExecutionError(`no signed url returned for attachment ${id}`);\n// after\nif (!url) throw new CommandExecutionError(\n  `no signed url returned for attachment ${id}; response=${JSON.stringify(data)}`\n);","handlingStrategy":"try-catch","validationCode":"const data = Array.isArray(rows) ? rows[0] : rows;\nif (!data || typeof data.url !== 'string' || !data.url.startsWith('http')) {\n  console.error('Signed-URL resolution failed:', JSON.stringify(data));\n}","typeGuard":"const hasSignedUrl = (d) => typeof d?.url === 'string' && d.url.length > 0;","tryCatchPattern":"try {\n  await attachmentDownload(page, { attachmentId: id });\n} catch (e) {\n  if (/no signed url returned/.test(e.message)) {\n    console.error('Signed URL not issued — re-authenticate Slock session and verify the attachment exists');\n  } else throw e;\n}","preventionTips":["Keep the Slock browser session fresh; re-login before batch downloads","Confirm the attachment exists via a list/query command before downloading","Log the evaluate result payload so auth/schema failures are visible, not just 'no url'","Pin/verify the --server slug matches the environment holding the attachment"],"tags":["browser-automation","http","auth","signed-url"],"backgroundTag":"missing-signed-url","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}