{"record":{"id":"285d613942cf2bf7","repo":"jackwener/OpenCLI","slug":"midjourney-media-download-failed-http-payload","errorCode":null,"errorMessage":"Midjourney media download failed: HTTP ${payload?.status ?? 0} from ${url}","messagePattern":"Midjourney media download failed: HTTP (.+?) from (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":557,"sourceCode":"        // CDN is public but Cloudflare-protected. Browser-origin fetch succeeds\n        // with default same-origin credential mode; forcing cross-origin cookies\n        // turns it into a credentialed CORS request and Midjourney rejects it.\n        const response = await fetch(mediaUrl);\n        if (!response.ok) return { ok: false, status: response.status, type: response.headers.get('content-type') || '' };\n        const bytes = new Uint8Array(await response.arrayBuffer());\n        window[key] = bytes;\n        return {\n          ok: true,\n          status: response.status,\n          type: response.headers.get('content-type') || '',\n          size: bytes.length,\n        };\n      }, url, transferKey));\n    } catch (error) {\n      throw new CommandExecutionError(`Midjourney browser-context media fetch failed: ${errorMessage(error)}`);\n    }\n    if (!payload || typeof payload !== 'object' || !payload.ok) {\n      throw new CommandExecutionError(`Midjourney media download failed: HTTP ${payload?.status ?? 0} from ${url}`);\n    }\n    if (!String(payload.type || '').startsWith(expectedMimePrefix)) {\n      throw new CommandExecutionError(`Midjourney media download returned unexpected content type \"${payload.type || 'unknown'}\"`);\n    }\n    const size = Number(payload.size);\n    if (!Number.isInteger(size) || size <= 0) {\n      throw new CommandExecutionError(`Midjourney media download returned an empty file from ${url}`);\n    }\n\n    // Returning a complete base64 file in one Browser Bridge response can\n    // exceed the daemon message limit. Pull it out in bounded chunks instead.\n    const parts = [];\n    const chunkSize = 96 * 1024;\n    for (let offset = 0; offset < size; offset += chunkSize) {\n      const base64 = unwrapEvaluateResult(await page.evaluate((key, start, length) => {\n        const bytes = window[key];\n        if (!(bytes instanceof Uint8Array)) return null;\n        const chunk = bytes.subarray(start, Math.min(bytes.length, start + length));","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L539-L575","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const res = await fetch(url, { method: 'HEAD' });\nif (!res.ok) throw new Error('Media URL not ready: HTTP ' + res.status + ' for ' + url);","typeGuard":null,"tryCatchPattern":"try {\n  await downloadMedia(page, url);\n} catch (err) {\n  const m = err.message.match(/HTTP (\\d+)/);\n  if (m && ['429','500','502','503'].includes(m[1])) {\n    await sleep(backoff);\n    await downloadMedia(page, url); // retry transient statuses\n  } else if (m && ['403','404'].includes(m[1])) {\n    await downloadMedia(page, await resolveFreshUrl(jobId)); // expired URL\n  } else throw err;\n}","preventionTips":["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."],"tags":["http","network","cdn","midjourney"],"backgroundTag":"http-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}