jackwener/OpenCLI · error · Error
Image upload failed: ${msg}
Error message
Image upload failed: ${msg} What it means
Thrown by attachComposerImage when the CDP-based page.setFileInput bridge exists and is invoked, but fails with an error that is NOT a recoverable 'unknown action / not supported / not-allowed' condition (see isRecoverableFileInputError). Only non-recoverable failures get wrapped as `Image upload failed: ${msg}`; recoverable ones silently fall through to the base64 DataTransfer fallback.
Source
Thrown at clis/twitter/utils.js:139
* After upload it polls the DOM briefly to confirm the preview thumbnail
* actually rendered — without this, a 200 from setFileInput could mask a
* silent-no-attachment post.
*
* @param {object} page - OpenCLI page handle.
* @param {string} absImagePath - Already-validated absolute path.
* @param {string} [fileInputSelector] - Override (post.js historically used
* the same selector; default matches the X composer route).
*/
export async function attachComposerImage(page, absImagePath, fileInputSelector = COMPOSER_FILE_INPUT_SELECTOR) {
let uploaded = false;
if (page.setFileInput) {
try {
await page.setFileInput([absImagePath], fileInputSelector);
uploaded = true;
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
if (!isRecoverableFileInputError(msg)) {
throw new Error(`Image upload failed: ${msg}`);
}
// setFileInput not supported by extension — fall through to base64 fallback.
}
}
if (!uploaded) {
const ext = path.extname(absImagePath).toLowerCase();
const mimeType = ext === '.png'
? 'image/png'
: ext === '.gif'
? 'image/gif'
: ext === '.webp'
? 'image/webp'
: 'image/jpeg';
const base64 = fs.readFileSync(absImagePath).toString('base64');
if (base64.length > 500_000) {
console.warn(`[warn] Image base64 payload is ${(base64.length / 1024 / 1024).toFixed(1)}MB. ` +
'This may fail with the browser bridge. Update the extension to v1.6+ for CDP-based upload, ' +
'or compress the image before attaching.');View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command after reloading the composer page so the file input exists again
- Check that the file input selector (default COMPOSER_FILE_INPUT_SELECTOR or your override) matches the current X compose DOM
- Update the OpenCLI browser extension to the latest version so setFileInput behaves as expected
- If the wrapped message indicates a browser/CDP failure, restart the browser session and retry; as a last resort compress the image so the base64 fallback path is viable
Defensive patterns
Strategy: try-catch
Validate before calling
if (!fs.existsSync(absImagePath) || !path.isAbsolute(absImagePath)) throw new Error('Provide an absolute path to an existing image before calling attachComposerImage'); Type guard
function isRecoverableUploadError(err) {
const msg = err instanceof Error ? err.message : String(err);
return /unknown action|not supported|not[-\s]?allowed|notallowederror/i.test(msg);
} Try / catch
try {
await attachComposerImage(page, absPath);
} catch (err) {
if (err.message.startsWith('Image upload failed:') && !isRecoverableFileInputError(err.message)) {
console.error('CDP setFileInput failed:', err.message);
// reload the composer page or update the extension, then retry
} else { throw err; }
} Prevention
- Keep the OpenCLI browser extension up to date so setFileInput is available and stable
- Reload the compose page before attaching so the file input selector resolves
- Avoid overriding fileInputSelector unless you have verified the current DOM
- Retry once after a page reload — many bridge failures are transient DOM timing issues
When it happens
Trigger: page.setFileInput([absImagePath], selector) throws for reasons outside the recoverable regex: the composer file input selector matches nothing in the CDP bridge, the page/extension bridge errors mid-injection, a protocol/timeout error from the browser, or a permissions failure not phrased as NotAllowedError.
Common situations: Stale DOM after X re-renders the composer so the selector no longer resolves; outdated or missing OpenCLI browser extension producing unexpected bridge errors; browser crashed or tab navigated away mid-upload; selector override argument pointing at the wrong page's input.
Related errors
- Image upload failed: ${upload?.error ?? 'unknown error'}
- Image upload failed: preview did not appear.
- amazon ${action} navigation lost the current browser target
- ChatGPT model selection requires native browser click suppor
- ChatGPT tool selection requires native browser click support
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/dc7dba9af106bcab.
Report an issue: GitHub.