jackwener/OpenCLI · error · CommandExecutionError
Midjourney media download failed: HTTP ${payload?.status ??
Error message
Midjourney media download failed: HTTP ${payload?.status ?? 0} from ${url} What it means
The in-page fetch completed but the payload reported ok=false (or no payload), meaning the CDN returned a non-2xx HTTP status. The error surfaces the actual HTTP status code and the URL so you can see why the media could not be downloaded.
Source
Thrown at clis/midjourney/utils.js:557
// CDN is public but Cloudflare-protected. Browser-origin fetch succeeds
// with default same-origin credential mode; forcing cross-origin cookies
// turns it into a credentialed CORS request and Midjourney rejects it.
const response = await fetch(mediaUrl);
if (!response.ok) return { ok: false, status: response.status, type: response.headers.get('content-type') || '' };
const bytes = new Uint8Array(await response.arrayBuffer());
window[key] = bytes;
return {
ok: true,
status: response.status,
type: response.headers.get('content-type') || '',
size: bytes.length,
};
}, url, transferKey));
} catch (error) {
throw new CommandExecutionError(`Midjourney browser-context media fetch failed: ${errorMessage(error)}`);
}
if (!payload || typeof payload !== 'object' || !payload.ok) {
throw new CommandExecutionError(`Midjourney media download failed: HTTP ${payload?.status ?? 0} from ${url}`);
}
if (!String(payload.type || '').startsWith(expectedMimePrefix)) {
throw new CommandExecutionError(`Midjourney media download returned unexpected content type "${payload.type || 'unknown'}"`);
}
const size = Number(payload.size);
if (!Number.isInteger(size) || size <= 0) {
throw new CommandExecutionError(`Midjourney media download returned an empty file from ${url}`);
}
// Returning a complete base64 file in one Browser Bridge response can
// exceed the daemon message limit. Pull it out in bounded chunks instead.
const parts = [];
const chunkSize = 96 * 1024;
for (let offset = 0; offset < size; offset += chunkSize) {
const base64 = unwrapEvaluateResult(await page.evaluate((key, start, length) => {
const bytes = window[key];
if (!(bytes instanceof Uint8Array)) return null;
const chunk = bytes.subarray(start, Math.min(bytes.length, start + length));View on GitHub (pinned to 49907e53dc)
Solutions
- Re-resolve a fresh media URL for the job (signed URLs expire) and retry.
- Check the HTTP status in the message: 403/404 means URL expired or wrong; 429 means back off and retry later; 5xx means retry after a delay.
- Verify the jobId is correct.
- Reduce download concurrency to avoid CDN rate limits.
Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch(url, { method: 'HEAD' });
if (!res.ok) throw new Error('Media URL not ready: HTTP ' + res.status + ' for ' + url); Try / catch
try {
await downloadMedia(page, url);
} catch (err) {
const m = err.message.match(/HTTP (\d+)/);
if (m && ['429','500','502','503'].includes(m[1])) {
await sleep(backoff);
await downloadMedia(page, url); // retry transient statuses
} else if (m && ['403','404'].includes(m[1])) {
await downloadMedia(page, await resolveFreshUrl(jobId)); // expired URL
} else throw err;
} Prevention
- Download soon after job completion while signed URLs are fresh.
- Treat 429 with exponential backoff; limit parallel downloads.
- Verify jobId before constructing media URLs.
- Handle 403 by re-resolving the URL rather than retrying it.
When it happens
Trigger: The media URL returns 403 (expired signed CDN link), 404 (media deleted or wrong URL), 429 (rate limited), or 5xx (CDN error); payload came back null/not an object because the page returned something unexpected.
Common situations: Re-running downloads hours after job completion when signed URLs expired; mistyped or stale jobIds producing wrong URLs; Midjourney CDN rate limiting many parallel downloads.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
- 1point3acres request failed: HTTP ${res.status} ${res.status
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/285d613942cf2bf7.
Report an issue: GitHub.