{"record":{"id":"088ea6511306680d","repo":"jackwener/OpenCLI","slug":"midjourney-action-is-ambiguous-candidates-lengt","errorCode":null,"errorMessage":"Midjourney action is ambiguous; ${candidates.length} derived jobs matched parent ${parentJobId}","messagePattern":"Midjourney action is ambiguous; (.+?) derived jobs matched parent (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":504,"sourceCode":"      if (consecutivePollFailures >= 3) throw error;\n      if (!(await waitForNextPoll(page, deadline, 1.5))) break;\n      continue;\n    }\n    candidates = recent.filter((row) => {\n      const id = String(row?.id || '').toLowerCase();\n      const parent = String(row?.parent_id || '').toLowerCase();\n      const enqueuedAt = Date.parse(String(row?.enqueue_time || ''));\n      return UUID_RE.test(id)\n        && !baselineIds.has(id)\n        && parent === String(parentJobId).toLowerCase()\n        && Number.isFinite(enqueuedAt)\n        && enqueuedAt >= submittedAtMs - 5000;\n    });\n    if (candidates.length === 1) return String(candidates[0].id).toLowerCase();\n    if (!(await waitForNextPoll(page, deadline, 1.5))) break;\n  } while (true);\n  if (candidates.length > 1) {\n    throw new CommandExecutionError(\n      `Midjourney action is ambiguous; ${candidates.length} derived jobs matched parent ${parentJobId}`,\n      candidates.map((row) => jobUrl(row.id)).join(', '),\n    );\n  }\n  throw new TimeoutError('Midjourney derived job submission', timeoutSeconds, `No new child job appeared for ${parentJobId}.`);\n}\n\nexport async function waitForCompletedJob(page, jobId, timeoutSeconds) {\n  const deadline = Date.now() + timeoutSeconds * 1000;\n  let lastStatus = 'unknown';\n  do {\n    const job = await fetchJobStatus(page, jobId, { allowMissing: true });\n    if (job) {\n      lastStatus = String(job.current_status || job.status || 'unknown').toLowerCase();\n      if (lastStatus === 'completed') return job;\n      if (['failed', 'cancelled', 'canceled', 'error'].includes(lastStatus)) {\n        throw new CommandExecutionError(`Midjourney job ${jobId} ended with status \"${lastStatus}\"`);\n      }","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L486-L522","documentation":"After submitting a derived action (upscale/vary/reroll) on a parent job, the library polls for exactly one new child job enqueued at/after the action time. If more than one candidate child job matches the parent and timing window, CommandExecutionError is thrown listing the candidate URLs, since picking one would be a guess.","triggerScenarios":"Calling the derived-job flow when candidates.length > 1 — e.g. the same action was triggered twice (double-click/rerun), another session performed actions on the same parent, or multiple children legitimately spawned within the timing tolerance (submittedAtMs - 5000).","commonSituations":"Retrying a failed action command after the first actually succeeded (two children exist); parallel CLI sessions acting on the same parent image; grid actions generating multiple jobs within the window.","solutions":["Inspect the candidate job URLs in the error and continue with the intended child ID directly (e.g. via waitForCompletedJob).","Avoid re-running the action command after a timeout — the first run may have succeeded; check the parent's children on midjourney.com first.","Ensure no concurrent sessions are issuing actions on the same parent job.","Wait for unrelated child jobs from that parent to complete before re-attempting, so the matching window is unambiguous."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure no child jobs already exist from a prior attempt before re-issuing the action\nconst children = await fetchJobStatuses(page, recentJobIds).catch(() => []);\nconst priorChildren = children.filter((j) => String(j.parent_job_id || j.job_id || '') === parentJobId);\nif (priorChildren.length > 0) {\n  console.warn(`${priorChildren.length} child job(s) already exist for ${parentJobId}; track one by ID instead of re-running the action.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const childId = await deriveChildJobId(page, parentJobId, action);\n} catch (e) {\n  const m = String(e.message).match(/ambiguous; (\\d+) derived jobs/);\n  if (m) {\n    console.error('Choose the correct child from the listed URLs and continue with that ID.');\n  } else throw e;\n}","preventionTips":["Do not re-run action commands after a timeout without checking for existing children","Serialize all actions on a given parent within one session","Record child job IDs as soon as they are resolved for later retries","Wait for unrelated sibling jobs to leave the enqueued window before re-attempting"],"tags":["midjourney","ambiguity","derived-job"],"backgroundTag":"ambiguous-job-match","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}