{"record":{"id":"108b92b9f03df1b2","repo":"jackwener/OpenCLI","slug":"midjourney-submit-response-was-ambiguous-expected","errorCode":null,"errorMessage":"Midjourney submit response was ambiguous; expected ${expectedCount} new job(s), received ${ids.length}","messagePattern":"Midjourney submit response was ambiguous; expected (.+?) new job\\(s\\), received (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":150,"sourceCode":"    draft: flag('draft'),\n    raw: flag('raw'),\n  });\n}\n\nexport function submittedJobIdsFromCaptures(captures, expectedCount, baselineIds = new Set()) {\n  if (!Array.isArray(captures) || captures.length === 0) return [];\n  const successes = captures.flatMap((payload) => Array.isArray(payload?.success) ? payload.success : []);\n  const ids = [...new Set(successes\n    .map((row) => String(row?.job_id || '').toLowerCase())\n    .filter((id) => UUID_RE.test(id) && !baselineIds.has(id)))];\n  if (ids.length === expectedCount) return ids;\n  const failures = captures.flatMap((payload) => Array.isArray(payload?.failure) ? payload.failure : []);\n  if (failures.length && ids.length === 0) {\n    const detail = failures.map((row) => row?.message || row?.error || JSON.stringify(row)).join('; ');\n    throw new CommandExecutionError(`Midjourney rejected the submitted job: ${detail}`);\n  }\n  if (successes.length || ids.length) {\n    throw new CommandExecutionError(\n      `Midjourney submit response was ambiguous; expected ${expectedCount} new job(s), received ${ids.length}`,\n    );\n  }\n  return [];\n}\n\nexport function uploadedStorageUrlsFromCaptures(captures) {\n  if (!Array.isArray(captures)) return [];\n  const payloads = captures.flatMap((capture) => [capture, capture?.data, capture?.response].filter(Boolean));\n  return [...new Set(payloads.flatMap((payload) => {\n    const bucketPathname = String(payload?.bucketPathname || '').replace(/^\\/+/, '');\n    if (!/^[0-9a-f-]{36}\\/[0-9a-f]{32,}\\.(?:png|jpe?g|webp|gif)$/i.test(bucketPathname)) return [];\n    const thumbnailPath = bucketPathname.replace(/(\\.(?:png|jpe?g|webp|gif))$/i, '_384_N$1');\n    return [`${MIDJOURNEY_CDN}/u/${thumbnailPath}`];\n  }))];\n}\n\nexport function isVideoJob(job) {","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L132-L168","documentation":"Thrown by submittedJobIdsFromCaptures when some submit responses succeeded (successes or extracted ids exist) but fewer valid job UUIDs than expectedCount were recovered. The CLI cannot confirm whether the remaining jobs were created, so it refuses to return a partial result and reports expected vs received counts. This prevents silently losing track of submitted jobs.","triggerScenarios":"captures contain at least one success row or at least one valid UUID, but the count of unique UUIDs passing UUID_RE and not in baselineIds does not equal expectedCount. Typically a partial submit: some rows succeeded, some failed silently or returned unparseable job ids.","commonSituations":"Batch submits where Midjourney throttled part of the request, failure rows present but also some successes (so 2630 does not fire), or responses missing expected job_id fields due to an API response-shape change.","solutions":["Check the captured response payloads for failure rows explaining the missing jobs.","Resubmit only the missing jobs (diff expected vs received) after a short delay.","Log full submit responses during development to detect API shape changes.","Ensure baselineIds does not accidentally contain ids from the current batch."],"exampleFix":"// before\nconst ids = await submittedJobIdsFromCaptures(page, captures, 4); // may throw on 3 of 4\n// after\nconst ids = await submittedJobIdsFromCaptures(page, captures, 1); // submit smaller batches per call","handlingStrategy":"validation","validationCode":"const ids = captures.flatMap(c => [String(c?.job_id||'')]).filter(id => UUID_RE.test(id));\nif (ids.length !== expectedCount) console.warn(`precheck mismatch: expected ${expectedCount}, got ${ids.length}`);","typeGuard":"function isCompleteSubmitBatch(captures, expectedCount) {\n  const ids = new Set(captures.map(c => String(c?.job_id || '').toLowerCase()).filter(id => /^[0-9a-f-]{36}$/i.test(id)));\n  return ids.size === expectedCount;\n}","tryCatchPattern":"try {\n  const ids = await submittedJobIdsFromCaptures(page, captures, expected);\n} catch (err) {\n  const m = err.message.match(/expected (\\d+) new job\\(s\\), received (\\d+)/);\n  if (m) console.error(`Ambiguous submit: ${m[2]}/${m[1]} jobs confirmed — resubmit the missing ${m[1] - m[2]}`);\n  else throw err;\n}","preventionTips":["Keep batch sizes small so partial failures are rare","Record submitted job ids to reconcile expected vs received","Avoid including current-batch ids in baselineIds","Monitor Midjourney API response shapes in CI"],"tags":["midjourney","cli","partial-failure"],"backgroundTag":"api-response-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}