jackwener/OpenCLI · error · CommandExecutionError

no signed url returned for attachment ${id}

Error message

no signed url returned for attachment ${id}

What it means

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).

Source

Thrown at clis/slock/attachment-download.js:57

  columns: ['attachmentId', 'out', 'sizeBytes'],
  func: async (page, kwargs) => {
    const id = String(kwargs.attachmentId ?? '').trim();
    if (!UUID_RE.test(id)) throw new ArgumentError(`attachmentId "${id}" is not a UUID`);
    const out = path.resolve(String(kwargs.out ?? `./${id}.bin`));

    // Step 1 — in-page, resolve the signed URL with the user's Slock session.
    await page.goto(SLOCK_HOME_URL);
    const snippet = buildFetchSnippet({
      method: 'GET',
      path: `/attachments/${encodeURIComponent(id)}/url`,
      serverScoped: true,
      serverIdOverride: kwargs.server,
    });
    const result = await page.evaluate(`(async () => { ${snippet} })()`);
    const rows = dispatchEvaluateResult(result);
    const data = Array.isArray(rows) ? rows[0] : rows;
    const url = data?.url;
    if (!url) throw new CommandExecutionError(`no signed url returned for attachment ${id}`);

    // Step 2 — Node side, fetch the bytes from the signed CDN URL. No auth
    // header (URL is pre-signed); no Origin (Node fetch has none) so CORS
    // isn't in play.
    let res;
    try { res = await fetch(url); }
    catch (e) { throw new CommandExecutionError(`network error fetching signed URL: ${e.message}`); }
    if (!res.ok) {
      throw new CommandExecutionError(`HTTP ${res.status} from signed CDN URL while downloading ${id}`);
    }
    const ab = await res.arrayBuffer();
    fs.writeFileSync(out, Buffer.from(ab));
    return [{ attachmentId: id, out, sizeBytes: ab.byteLength }];
  },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate / refresh the Slock browser session so the in-page fetch carries valid cookies
  2. Verify the attachmentId exists and is accessible for the active or overridden server (--server)
  3. Inspect the raw dispatchEvaluateResult payload (log `result`/`data`) to see the actual error the server returned
  4. Update buildFetchSnippet if the API response schema changed and the URL is under a new key

Example fix

// before
if (!url) throw new CommandExecutionError(`no signed url returned for attachment ${id}`);
// after
if (!url) throw new CommandExecutionError(
  `no signed url returned for attachment ${id}; response=${JSON.stringify(data)}`
);
Defensive patterns

Strategy: try-catch

Validate before calling

const data = Array.isArray(rows) ? rows[0] : rows;
if (!data || typeof data.url !== 'string' || !data.url.startsWith('http')) {
  console.error('Signed-URL resolution failed:', JSON.stringify(data));
}

Type guard

const hasSignedUrl = (d) => typeof d?.url === 'string' && d.url.length > 0;

Try / catch

try {
  await attachmentDownload(page, { attachmentId: id });
} catch (e) {
  if (/no signed url returned/.test(e.message)) {
    console.error('Signed URL not issued — re-authenticate Slock session and verify the attachment exists');
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9b9358c96c12be86. Report an issue: GitHub.