JuliusBrussee/caveman · error · Error
cave_harness_model_invalid
cave_harness_model_invalid
Error message
cave_harness_model_invalid
What it means
Thrown while preparing a locked harness (packages/agent/src/execution-kernel.ts:94): the selected plan's model string does not split into a non-empty provider and a non-empty model. The framework expects 'provider/model' format (e.g. 'anthropic/claude-sonnet-4-5'); splitting on the first '/' must leave both parts non-empty.
Source
Thrown at packages/agent/src/execution-kernel.ts:94
throw new Error("cave_harness_build_mismatch");
}
if (input.agentId !== undefined && build.agent_id !== input.agentId) {
throw new Error("cave_harness_agent_mismatch");
}
if (stableStringify(input.plan) !== stableStringify(build.selected_plan)) {
throw new Error("cave_harness_plan_mismatch");
}
const planSHA256 = sha256(stableStringify(input.plan));
if (planSHA256 !== build.plan_sha256) {
throw new Error("cave_harness_plan_digest_mismatch");
}
const contextIRSHA256 = sha256(stableStringify(contextIRToWire(input.contextIR)));
if (contextIRSHA256 !== build.context_ir_sha256) {
throw new Error("cave_harness_context_ir_mismatch");
}
const [provider, ...modelParts] = input.plan.model.split("/");
const model = modelParts.join("/");
if (!provider || !model) throw new Error("cave_harness_model_invalid");
return Object.freeze({
build,
plan: build.selected_plan,
planSHA256,
contextIRSHA256,
provider,
model,
});
}
export interface ProviderUsageEvidence {
provider: string;
model: string;
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
cacheWriteTokens: number;
reasoningTokens: number;View on GitHub (pinned to 27d5a3981a)
Solutions
- Set the model to a 'provider/model' string, e.g. 'anthropic/claude-sonnet-4-5'.
- If the model comes from configuration, validate it matches /^[^/]+\/.+$/ before building/running.
- Use the framework's model helpers/typed model constants instead of raw strings where available.
Example fix
// before
agent({ model: "claude-sonnet-4-5", /* ... */ });
// after
agent({ model: "anthropic/claude-sonnet-4-5", /* ... */ }); Defensive patterns
Strategy: type-guard
Validate before calling
const MODEL_RE = /^[^/]+\/.+$/;
function parseProviderModel(model: string): { provider: string; model: string } | null {
const idx = model.indexOf("/");
if (idx <= 0 || idx === model.length - 1) return null;
return { provider: model.slice(0, idx), model: model.slice(idx + 1) };
}
const parsed = parseProviderModel(plan.model);
if (!parsed) throw new Error("model must be 'provider/model'"); Type guard
function isQualifiedModel(value: unknown): value is string {
return typeof value === "string" && /^[^/]+\/.+$/.test(value) && !value.endsWith("/");
} Prevention
- Always configure models as 'provider/model' (e.g. 'anthropic/claude-sonnet-4-5').
- Validate model strings from env vars/config with a regex before passing them to agent().
- Centralize model constants in one module instead of scattering raw strings.
When it happens
Trigger: plan.model is a bare model name with no slash ('claude-sonnet-4-5'), starts or ends with '/' ('/model', 'anthropic/'), or is the empty string.
Common situations: Hand-writing a model string without the provider prefix; configuring the model from an env var that is empty or unpopulated; copying a model id from provider docs that omits the vendor prefix; string-manipulation bugs trimming the provider segment.
Related errors
- cave_tool_sandbox_entry_required
- option not found
- cave_harness_adapter_version_invalid
- cave_harness_model_invalid
- cave_harness_model_identity_missing
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/8ed8a7d08767ae5a.
Report an issue: GitHub.