jackwener/OpenCLI · error · CommandExecutionError
Midjourney budget guard would leave ${Number((remainingMinut
Error message
Midjourney budget guard would leave ${Number((remainingMinutes - estimatedMinutes).toFixed(2))} minutes, below the ${reserve}-minute reserve What it means
assertBudget also enforces a --reserve-minutes floor (default 0) on the account's remaining Fast GPU minutes. This CommandExecutionError is thrown when spending estimatedMinutes would leave the balance below the reserve, computed from account.total_credits/credits_total via creditsToMinutes. Unlike 2598 it is a runtime account-state guard, not an argument validation.
Source
Thrown at clis/midjourney/capabilities.js:284
effectiveModel: selectedModel,
routingReason,
resolution,
speed,
repeat,
estimatedMinutes,
};
}
export function assertBudget(account, estimatedMinutes, maxMinutes, reserveMinutes, creditsToMinutes) {
const max = normalizeNonNegativeNumber(maxMinutes, 2, '--max-minutes');
const reserve = normalizeNonNegativeNumber(reserveMinutes, 0, '--reserve-minutes');
if (estimatedMinutes > max) {
throw new ArgumentError(`Estimated GPU cost ${estimatedMinutes} minutes exceeds --max-minutes ${max}`);
}
const remainingCredits = Number(account?.total_credits ?? account?.credits_total);
const remainingMinutes = creditsToMinutes(remainingCredits);
if (Number.isFinite(remainingMinutes) && remainingMinutes - estimatedMinutes < reserve) {
throw new CommandExecutionError(
`Midjourney budget guard would leave ${Number((remainingMinutes - estimatedMinutes).toFixed(2))} minutes, below the ${reserve}-minute reserve`,
);
}
return { maxMinutes: max, reserveMinutes: reserve, remainingMinutes };
}
export function estimateAction(
operation,
{ videoResolution = 'sd', batchSize = 1, sourceIsVideo = false, sourceUsesOmni = false } = {},
) {
if (!ACTION_CHOICES.includes(operation)) {
throw new ArgumentError(`operation must be one of: ${ACTION_CHOICES.join(', ')}`);
}
if (operation === 'open-editor' || operation === 'cancel') return 0;
if (operation === 'rerun' && sourceIsVideo) {
if (!['sd', 'hd'].includes(videoResolution)) throw new ArgumentError('--video-resolution must be sd or hd');
if (![1, 2, 4].includes(batchSize)) throw new ArgumentError('--batch-size must be 1, 2, or 4');
return GPU_COST_MINUTES[`video${videoResolution === 'hd' ? 'Hd' : 'Sd'}${batchSize}`];View on GitHub (pinned to 49907e53dc)
Solutions
- Wait for the subscription's GPU minutes to reset or purchase more Fast GPU time, then retry.
- Lower --reserve-minutes if the configured headroom is stricter than you need (e.g. --reserve-minutes 0).
- Reduce estimated cost: fewer repeats, drop turbo/hd/omni, or use relax speed (0 GPU minutes).
- Check remaining GPU minutes via the account endpoint before submitting and skip the job if remaining - estimate < reserve.
Example fix
// before midjourney generate 'a cat --r 4' --reserve-minutes 10 // only 6 minutes left // after midjourney generate 'a cat --r 2' --reserve-minutes 2
Defensive patterns
Strategy: try-catch
Validate before calling
const account = await midjourney.account();
const remainingMinutes = account.gpuMinutesAvailable; // or creditsToMinutes(total_credits)
const reserve = Number(args.reserveMinutes ?? 0);
if (remainingMinutes - estimatedMinutes < reserve) {
throw new Error(`would leave ${remainingMinutes - estimatedMinutes} min, below ${reserve}-min reserve; top up or lower reserve`);
} Type guard
function hasHeadroom(account, estimatedMinutes, reserve, creditsToMinutes) {
const credits = Number(account?.total_credits ?? account?.credits_total);
const remaining = creditsToMinutes(credits);
return Number.isFinite(remaining) && remaining - estimatedMinutes >= reserve;
} Try / catch
try {
return await generate(args);
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('budget guard would leave')) {
const left = Number(err.message.match(/would leave ([\d.]+)/)[1]);
const reserve = Number(err.message.match(/below the ([\d.]+)-minute/)[1]);
if (left < 0) throw new Error('insufficient GPU minutes; waiting for reset');
return generate({ ...args, repeat: 1, reserveMinutes: Math.max(0, reserve - 1) });
}
throw err;
} Prevention
- Check remaining GPU minutes via the account endpoint before every submission.
- Set --reserve-minutes intentionally (0 if headroom is not needed), not as an arbitrary large number.
- Prefer relax speed near the end of a billing cycle; it costs 0 fast GPU minutes.
- Wrap automated batches so they abort early instead of draining the balance below the reserve.
When it happens
Trigger: Calling the generate flow when remainingMinutes - estimatedMinutes < reserveMinutes: e.g. account has 3 GPU minutes left, job estimates 1.5, and --reserve-minutes 2; or reserve set equal to/above the whole balance.
Common situations: Accounts nearly out of Fast GPU time at end of billing cycle; scripts setting a conservative --reserve-minutes to keep headroom for interactive use; running large --repeat batches that drain the balance below the configured floor.
Related errors
- medium tag request failed: ${err?.message ?? err}
- medium tag returned HTTP ${resp.status}
- Browser session required for medium posts
- ${capabilities.plan || 'current'} plan allows at most ${capa
- Estimated GPU cost ${estimatedMinutes} minutes exceeds --max
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/59f6cdd88646c14a.
Report an issue: GitHub.