jackwener/OpenCLI · error · CommandExecutionError

Failed to upload image to ChatGPT: ${err instanceof Error ?

Error message

Failed to upload image to ChatGPT: ${err instanceof Error ? err.message : String(err)}

What it means

uploadChatGPTImages threw inside the command, so it is wrapped into a CommandExecutionError prefixed 'Failed to upload image to ChatGPT: <underlying message>'. This is the exception path (as opposed to the {ok:false} path of error 627) — the upload helper itself raised, e.g. the attachment button/input was not found or a DOM interaction failed.

Source

Thrown at clis/chatgpt/image.js:109

        const preparedImages = imagePaths.length ? await prepareChatGPTImagePaths(imagePaths) : { ok: true, paths: [] };
        if (!preparedImages.ok) {
            throw new ArgumentError(preparedImages.reason);
        }

        // Navigate with full reload to clear React sidebar state before editing the draft.
        if (kwargs.project) {
            await navigateToProject(page, kwargs.project);
        } else {
            await page.goto(`https://${CHATGPT_DOMAIN}/new`, { settleMs: 2000 });
        }
        await clearChatGPTDraft(page);

        if (imagePaths.length) {
            let upload;
            try {
                upload = await uploadChatGPTImages(page, preparedImages.paths);
            } catch (err) {
                throw new CommandExecutionError(`Failed to upload image to ChatGPT: ${err instanceof Error ? err.message : String(err)}`);
            }
            if (!upload?.ok) throw new CommandExecutionError(upload?.reason || 'Failed to upload image to ChatGPT');
        }

        const beforeUrls = await getChatGPTVisibleImageUrls(page);

        // Send an explicit generation/editing prompt so ChatGPT returns image assets.
        const sent = await sendChatGPTMessage(page, buildPrompt(prompt, imagePaths.length));
        if (!sent) {
            throw new CommandExecutionError(
                'Failed to send image prompt to ChatGPT',
                `Open ${await currentChatGPTLink(page)} and verify the composer is ready.`,
            );
        }

        // ChatGPT briefly navigates to /c/{id} after sending, then may
        // redirect back to the home page. Poll until we capture the /c/ URL.
        let convUrl = '';

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the suffixed underlying message — it identifies the failing DOM step.
  2. Retry the command; transient composer/hydration issues often clear on a second run.
  3. Verify the composer is visible and usable in a browser session first.
  4. Check file size/format against ChatGPT upload limits.
  5. If it fails consistently, the upload selectors likely changed — update the library.

Example fix

// before
opencli chatgpt image "enhance" --image ./big-50mb.png   # upload throws mid-flight
// after
# resize/compress the image below ChatGPT limits, then
opencli chatgpt image "enhance" --image ./resized.png
Defensive patterns

Strategy: try-catch

Validate before calling

// Warm up the composer before uploading: navigate and confirm the page is interactive
await run('chatgpt image', prompt, '--image', path); // wrap with retry below

Type guard

null

Try / catch

async function uploadWithRetry(cmd, attempt = 0) {
  try {
    return await run('chatgpt image', cmd.prompt, '--image', cmd.image);
  } catch (err) {
    const msg = String(err.message);
    if (msg.includes('Failed to upload image to ChatGPT:') && attempt < 2) {
      await sleep(15_000 * (attempt + 1));
      return uploadWithRetry(cmd, attempt + 1);
    }
    throw err;
  }
}

Prevention

When it happens

Trigger: `opencli chatgpt image "prompt" --image <path>` where uploadChatGPTImages(page, preparedImages.paths) throws — composer not rendered, attachment file input missing, page navigated mid-upload, or a Playwright/DOM error during the upload interaction.

Common situations: ChatGPT UI changed so the upload control selector is stale; page not fully hydrated when upload starts; file too large triggering a ChatGPT-side error that surfaces as an exception; transient network failure during upload; composer in an unexpected state (leftover draft or dialog).

Related errors


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