{"record":{"id":"9b87c52f953bd02f","repo":"jackwener/OpenCLI","slug":"midjourney-kind-returned-invalid-media-bytes-e","errorCode":null,"errorMessage":"Midjourney ${kind} returned invalid media bytes; expected ${config.mime}, detected ${actualMime || 'unknown'}","messagePattern":"Midjourney (.+?) returned invalid media bytes; expected (.+?), detected (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":777,"sourceCode":"  if (!downloaded?.downloaded || downloaded.state !== 'complete' || !downloaded.filename) {\n    throw new CommandExecutionError(`Midjourney ${kind} download did not complete: ${downloaded?.error || downloaded?.state || 'unknown'}`);\n  }\n  const sourcePath = path.resolve(String(downloaded.filename));\n  const sourceStat = await fs.stat(sourcePath).catch(() => null);\n  if (!sourceStat?.isFile() || sourceStat.size <= 0) {\n    throw new CommandExecutionError(`Browser reported a completed download but the file is missing: ${sourcePath}`);\n  }\n  const handle = await fs.open(sourcePath, 'r');\n  let actualMime;\n  try {\n    const header = Buffer.alloc(16);\n    const { bytesRead } = await handle.read(header, 0, header.length, 0);\n    actualMime = sniffMediaMime(header.subarray(0, bytesRead));\n  } finally {\n    await handle.close();\n  }\n  if (actualMime !== config.mime) {\n    throw new CommandExecutionError(\n      `Midjourney ${kind} returned invalid media bytes; expected ${config.mime}, detected ${actualMime || 'unknown'}`,\n    );\n  }\n  if (downloaded.mime && downloaded.mime !== actualMime) {\n    log.warn(`Browser Bridge reported ${downloaded.mime} for ${sourcePath}; detected ${actualMime} from file bytes`);\n  }\n  const tempPath = `${filePath}.part-${process.pid}-${Date.now()}`;\n  try {\n    await fs.copyFile(sourcePath, tempPath);\n    await fs.rename(tempPath, filePath);\n    if (sourcePath !== filePath) await fs.unlink(sourcePath).catch(() => {});\n  } catch (error) {\n    await fs.unlink(tempPath).catch(() => {});\n    throw new CommandExecutionError(`Could not store Midjourney ${kind} at ${filePath}: ${errorMessage(error)}`);\n  }\n  return {\n    index,\n    kind,","sourceCodeStart":759,"sourceCodeEnd":795,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L759-L795","documentation":"A CommandExecutionError thrown when the downloaded rendered video's magic bytes do not match the expected MIME for the requested kind — video/mp4 for 'video-social' or image/gif for 'gif'. Like the raw-video check, this prevents saving HTML error pages or wrongly-typed responses as media files.","triggerScenarios":"After a reported-complete download, sniffMediaMime(header) on the first bytes of the file returns anything other than config.mime (e.g. HTML masquerading as a download, or the browser saved a PNG when GIF was requested).","commonSituations":"Midjourney served an error/redirect page that the browser saved as the download; the 'Download as GIF' menu actually produces a WebP/APNG in a newer UI; the social MP4 export returned a WebM; corrupted or truncated file whose header doesn't parse.","solutions":["Compare the detected actualMime in the message with what Midjourney's UI really produces and update config.mime/extension if the format changed","Re-authenticate and retry — an HTML result usually means the session dropped","Open the downloaded file in a hex editor to confirm the actual format and adjust the sniffer if it's a valid but unrecognized variant","Check file size — a tiny file is likely an error page, not media","Retry the download; transient failures can yield empty/HTML bodies"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"async function sniffIsKind(filePath, kind) {\n  const fh = await fs.promises.open(filePath, 'r');\n  try {\n    const header = Buffer.alloc(16);\n    const { bytesRead } = await fh.read(header, 0, 16, 0);\n    const mime = sniffMediaMime(header.subarray(0, bytesRead));\n    const expected = kind === 'gif' ? 'image/gif' : 'video/mp4';\n    return mime === expected;\n  } finally { await fh.close(); }\n}","typeGuard":"function isGifHeader(buf) {\n  return buf.subarray(0, 3).toString('binary') === 'GIF';\n}\nfunction isMp4Header(buf) {\n  return buf.length > 11 && buf.subarray(4, 8).toString('binary') === 'ftyp';\n}","tryCatchPattern":"try {\n  await downloadRenderedVideo(page, jobId, i, kind, outDir);\n} catch (err) {\n  if (err.message.includes('invalid media bytes')) {\n    const m = err.message.match(/detected ([^\\s]+)/);\n    console.error(`Midjourney sent ${m?.[1]} for kind '${kind}' — check for UI format changes or a dropped session.`);\n  } else throw err;\n}","preventionTips":["Re-authenticate before export runs — HTML results usually mean a dropped session","Track Midjourney format changes (e.g. GIF menu now serving WebP) and update expected MIME configs","Reject suspiciously small downloads (likely error pages) before validation","Keep a sample of the failed file for format debugging"],"tags":["midjourney","media-download","mime-validation","magic-bytes"],"backgroundTag":"invalid-media-bytes","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}