JuliusBrussee/caveman · error · Error
cave_harness_model_invalid
cave_harness_model_invalid
Error message
cave_harness_model_invalid
What it means
The harness plan's `model` field must be a `provider/model` string with a non-empty provider segment before the first `/` and a non-empty model segment after it. `expectedProviderModel` splits on the first `/` to derive the provider identity used for usage and cost validation; a bare model name or a leading/trailing slash has no unambiguous provider, so the adapter fails closed. This indicates the plan handed to the adapter was constructed or edited incorrectly.
Source
Thrown at packages/agent/src/adapters.ts:501
runtime.modelId.startsWith("dynamic:")) {
throw new Error("cave_eve_runtime_identity_missing");
}
const separator = runtime.modelId.indexOf("/");
if (separator < 1 || separator === runtime.modelId.length - 1 ||
typeof runtime.eveVersion !== "string" || runtime.eveVersion.length === 0) {
throw new Error("cave_eve_runtime_identity_missing");
}
return {
provider: runtime.modelId.slice(0, separator),
model: runtime.modelId.slice(separator + 1),
upstreamVersion: runtime.eveVersion,
};
}
function expectedProviderModel(plan: CavePlan): { provider: string; model: string } {
const separator = plan.model.indexOf("/");
if (separator < 1 || separator === plan.model.length - 1) {
throw new Error("cave_harness_model_invalid");
}
return { provider: plan.model.slice(0, separator), model: plan.model.slice(separator + 1) };
}
function normalizedResponseModel(value: unknown, provider: string): string {
if (typeof value !== "string" || value.length === 0) {
throw new Error("cave_harness_model_identity_missing");
}
return value.startsWith(`${provider}/`) ? value.slice(provider.length + 1) : value;
}
function terminalFinishReason(value: unknown): boolean {
return typeof value === "string" && ["stop", "length", "content-filter", "other"].includes(value);
}
function record(value: unknown, error: string): Record<string, unknown> {
if (!isRecord(value)) throw new Error(error);
return value;View on GitHub (pinned to 27d5a3981a)
Solutions
- Set `plan.model` to the full `provider/model` form, e.g. `"openai/gpt-4o"` or `"anthropic/claude-sonnet-4-5"`.
- If the plan comes from your own config file, add a startup assertion that `model` matches `/^[^/]+\/.+[^/]$/` before invoking the adapter.
- Regenerate the plan via the framework compiler instead of hand-editing it.
Example fix
// before
const plan = { model: "claude-sonnet-4-5", /* ... */ };
// after
const plan = { model: "anthropic/claude-sonnet-4-5", /* ... */ }; Defensive patterns
Strategy: type-guard
Validate before calling
function isValidPlanModel(model: string): boolean {
const i = model.indexOf("/");
return i >= 1 && i < model.length - 1;
}
if (!isValidPlanModel(plan.model)) throw new Error("plan.model must be provider/model"); Type guard
function isProviderModel(value: string): value is `${string}/${string}` {
const i = value.indexOf("/");
return i >= 1 && i < value.length - 1;
} Try / catch
try {
await adapter.run(request);
} catch (err) {
if (err instanceof Error && err.message === "cave_harness_model_invalid") {
plan.model = `anthropic/${plan.model}`; // repair only if provider is genuinely known
}
} Prevention
- Type plan.model as `${string}/${string}` at the config boundary.
- Always compile plans through the framework rather than hand-writing them.
- Assert the provider/model shape in config-loading code before run time.
When it happens
Trigger: Passing a `CavePlan` whose `model` is `"claude-sonnet-4-5"` (no provider), `"/claude-sonnet-4-5"` (empty provider), `"anthropic/"` (empty model), or an empty string. Any call that lowers a plan into the Vercel/Eve/Mastra bridge hits this in `expectedProviderModel`.
Common situations: Hand-writing a plan instead of compiling one through the framework; copying a model name from a provider console (bare names like `gpt-4o`) into plan config; a config loader trimming or mangling the `provider/model` value; changing model naming conventions between environments.
Related errors
- cave_harness_model_identity_missing
- cave_harness_wire_contract_invalid
- cave_harness_signal_invalid
- caveman-code: model must use provider/model format
- option not found
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/514de8bb26fa60c0.
Report an issue: GitHub.