jackwener/OpenCLI · error · TimeoutError

Midjourney derived job submission

Error message

Midjourney derived job submission

What it means

TimeoutError raised when the derived-job polling loop ends without any new child job appearing for the parent (candidates never reached 1 and never exceeded 1). The operation name identifies the phase and the detail names the parent job ID that produced no child.

Source

Thrown at clis/midjourney/utils.js:509

      const id = String(row?.id || '').toLowerCase();
      const parent = String(row?.parent_id || '').toLowerCase();
      const enqueuedAt = Date.parse(String(row?.enqueue_time || ''));
      return UUID_RE.test(id)
        && !baselineIds.has(id)
        && parent === String(parentJobId).toLowerCase()
        && Number.isFinite(enqueuedAt)
        && enqueuedAt >= submittedAtMs - 5000;
    });
    if (candidates.length === 1) return String(candidates[0].id).toLowerCase();
    if (!(await waitForNextPoll(page, deadline, 1.5))) break;
  } while (true);
  if (candidates.length > 1) {
    throw new CommandExecutionError(
      `Midjourney action is ambiguous; ${candidates.length} derived jobs matched parent ${parentJobId}`,
      candidates.map((row) => jobUrl(row.id)).join(', '),
    );
  }
  throw new TimeoutError('Midjourney derived job submission', timeoutSeconds, `No new child job appeared for ${parentJobId}.`);
}

export async function waitForCompletedJob(page, jobId, timeoutSeconds) {
  const deadline = Date.now() + timeoutSeconds * 1000;
  let lastStatus = 'unknown';
  do {
    const job = await fetchJobStatus(page, jobId, { allowMissing: true });
    if (job) {
      lastStatus = String(job.current_status || job.status || 'unknown').toLowerCase();
      if (lastStatus === 'completed') return job;
      if (['failed', 'cancelled', 'canceled', 'error'].includes(lastStatus)) {
        throw new CommandExecutionError(`Midjourney job ${jobId} ended with status "${lastStatus}"`);
      }
    }
    if (!(await waitForNextPoll(page, deadline, 2))) break;
  } while (true);
  throw new TimeoutError(
    `Midjourney job ${jobId} (last status: ${lastStatus})`,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify on midjourney.com whether the child job exists; if it does, wait on it directly by ID instead of retrying the action.
  2. Increase timeoutSeconds to account for slow queue registration and retry the action once.
  3. Re-open/refresh the parent job page and re-trigger the action — stale page context can make the click a no-op.
  4. Confirm the parent job is in a state that permits the action (not failed/expired).

Example fix

// before
await submitDerivedAction(page, parentJobId, 'upscale', { timeoutSeconds: 20 });
// after
await submitDerivedAction(page, parentJobId, 'upscale', { timeoutSeconds: 90 }); // tolerate slow child registration
Defensive patterns

Strategy: retry

Validate before calling

// verify the parent is actionable before attempting a derived submission
const parent = await fetchJobStatus(page, parentJobId).catch(() => null);
if (!parent) throw new Error(`Parent ${parentJobId} not found; derived action impossible.`);
const st = String(parent.current_status || parent.status || '').toLowerCase();
if (st !== 'completed') throw new Error(`Parent status is ${st}; only completed jobs accept actions.`);

Try / catch

async function deriveWithRetry(page, parentJobId, action, timeoutSeconds) {
  try {
    return await submitDerivedAction(page, parentJobId, action, { timeoutSeconds });
  } catch (e) {
    if (String(e.message).includes('derived job submission')) {
      await page.reload({ waitUntil: 'networkidle' }); // fix stale click context
      return submitDerivedAction(page, parentJobId, action, { timeoutSeconds: timeoutSeconds * 2 });
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: The deadline expires with no new child job enqueued after submittedAtMs - 5000 for parentJobId: the action click/submit silently failed, the child job was rejected server-side, or the child appeared outside the timing window (clock skew or delayed registration beyond timeoutSeconds).

Common situations: Midjourney UI action not actually triggering (button state/overlay issue in the driven page); very congested queue delaying child registration past the timeout; action performed on a job whose grid children were already all generated earlier (outside the window).

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/5d6934abd04ea9ab. Report an issue: GitHub.