JuliusBrussee/caveman · error · Error
cave_run_deadline_invalid
cave_run_deadline_invalid
Error message
cave_run_deadline_invalid
What it means
RunOptions.deadlineMs sets a wall-clock deadline for the run, stopping at the same between-call points as budget exhaustion. streamAgentInternal validates it: it must be a safe integer greater than 0. Zero, negative, fractional, or non-finite values throw before any execution.
Solutions
- Pass a positive safe integer of milliseconds, e.g. deadlineMs: 60000.
- Omit deadlineMs entirely when no deadline is wanted — do not use 0.
- Sanitize derived values: Math.floor(remainingMs) and clamp to >= 1 before passing.
Example fix
// before
runAgent(def, input, { deadlineMs: process.env.DEADLINE_MS as unknown as number });
// after
const ms = Number.parseInt(process.env.DEADLINE_MS ?? "", 10);
runAgent(def, input, Number.isSafeInteger(ms) && ms > 0 ? { deadlineMs: ms } : {}); Defensive patterns
Strategy: validation
Validate before calling
function isValidDeadlineMs(v) {
return v === undefined || (Number.isSafeInteger(v) && v > 0);
} Type guard
function hasValidDeadline(o) {
return o.deadlineMs === undefined ||
(Number.isSafeInteger(o.deadlineMs) && o.deadlineMs > 0);
} Try / catch
try {
await runAgent(def, input, opts);
} catch (err) {
if (err.message === "cave_run_deadline_invalid") {
await runAgent(def, input, { ...opts, deadlineMs: undefined }); // run without deadline
} else throw err;
} Prevention
- Omit deadlineMs rather than passing 0 for "no deadline".
- Use Math.floor on derived remaining-time values.
- Coerce env/config strings with parseInt and validate before use.
When it happens
Trigger: Passing deadlineMs: 0 (to mean "no deadline"), a negative duration, a fractional ms value, NaN/Infinity, or a numeric string from env/CLI config.
Common situations: Using 0 as a sentinel for "unlimited" (the correct way is to omit the option); computing the deadline from Date subtraction producing a float or negative remainder; reading ms durations from config as strings.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- cave_subagent_concurrency_limit_invalid
- cave_subagent_depth_limit_invalid
- cave_subagent_invocation_limit_invalid
- caveman agent: tool timeoutMs must be a positive integer
- caveman build: runner timeout must be a positive integer
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e5205ab37e2452e0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/runtime.ts:1085
throw new Error("cave_subagent_concurrency_limit_invalid");
}
if (options.lockedBuild !== undefined && options.candidatePlan !== undefined) {
throw new Error("cave_execution_authorization_ambiguous");
}
// Budget shape is settled before anything else happens: an ambiguous or
// unbounded budget must fail at run() start, not after the first dollar.
// maxCostUsd and budget are two different contracts for the same money —
// one terminates with an error, the other returns a planned partial result —
// so carrying both would leave the run's own stop semantics undecided.
if (options.budget !== undefined && options.maxCostUsd !== undefined) {
throw new Error("cave_budget_conflicting_cap");
}
const budgetMeter = executionContext.budgetMeter ?? (options.budget === undefined
? undefined
: new BudgetMeter(normalizeRunBudget(options.budget)));
if (options.deadlineMs !== undefined &&
(!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0)) {
throw new Error("cave_run_deadline_invalid");
}
if (options.maxSubagentDepth !== undefined &&
(!Number.isSafeInteger(options.maxSubagentDepth) || options.maxSubagentDepth <= 0 ||
options.maxSubagentDepth > ABSOLUTE_SUBAGENT_DEPTH_LIMIT)) {
throw new Error("cave_subagent_depth_limit_invalid");
}
const deadlineAt = executionContext.deadlineAt ?? (options.deadlineMs === undefined
? undefined
: performance.now() + options.deadlineMs);
// A controller with nothing to release would be a silent no-op at the
// checkpoint that expected it to matter.
if (options.budgetController !== undefined && budgetMeter === undefined) {
throw new Error("cave_budget_controller_without_budget");
}
const breakers = options.breakers === undefined
? undefined
: new BreakerState(normalizeRunBreakers(options.breakers, budgetMeter !== undefined));
const efficiencyPlan = options.lockedBuild?.selected_plan ?? options.candidatePlan;View on GitHub (pinned to 3ee70a1026)