jackwener/OpenCLI · error · CommandExecutionError

no signed url returned for attachment ${id}

Error message

no signed url returned for attachment ${id}

What it means

This CommandExecutionError is thrown after the in-page fetch for GET /attachments/:id/url completes successfully but the returned payload contains no `url` field. It indicates the server responded without the signed URL the CLI contract expects — either contract drift, an unexpected response shape, or a deleted/expired attachment.

Source

Thrown at clis/slock/attachment-url.js:45

    { name: 'attachmentId', positional: true, required: true, help: 'Attachment UUID' },
    { name: 'server', help: 'Override active server slug' },
  ],
  columns: ['attachmentId', 'url', 'expiresAt'],
  func: async (page, kwargs) => {
    const id = String(kwargs.attachmentId ?? '').trim();
    if (!UUID_RE.test(id)) throw new ArgumentError(`attachmentId "${id}" is not a UUID`);
    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;
    if (!data?.url) {
      throw new CommandExecutionError(`no signed url returned for attachment ${id}`);
    }
    return [{
      attachmentId: id,
      url: data?.url ?? null,
      expiresAt: data?.expiresAt ?? null,
    }];
  },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-list attachments to confirm the attachmentId still exists and is accessible.
  2. Check the Slock server API version; if `/attachments/:id/url` changed shape, update the CLI.
  3. Retry after re-authenticating — verify the session with auth-verify in case permissions silently degraded.
  4. If it persists, inspect the raw response (the error implies contract drift) and report/patch dispatchEvaluateResult mapping.
Defensive patterns

Strategy: try-catch

Type guard

const hasSignedUrl = (data) => data != null && typeof data === 'object' && typeof data.url === 'string' && data.url.length > 0;

Try / catch

try {
  const [row] = await attachmentUrl(page, id);
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('no signed url returned')) {
    console.error(`Attachment ${id} has no signed URL — verify it still exists`);
  } else throw e;
}

Prevention

When it happens

Trigger: The dispatchEvaluateResult call returns an object whose `data.url` is undefined/null: server returns an empty object, a row missing `url`, or a null envelope for a nonexistent attachment.

Common situations: Requesting a URL for an attachment that was deleted or whose record lacks a stored file, an API version change renaming the `url` field, or the session lacking permission to mint signed URLs (server returns 200 with empty body).

Related errors


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