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

  1. Set `plan.model` to the full `provider/model` form, e.g. `"openai/gpt-4o"` or `"anthropic/claude-sonnet-4-5"`.
  2. If the plan comes from your own config file, add a startup assertion that `model` matches `/^[^/]+\/.+[^/]$/` before invoking the adapter.
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/514de8bb26fa60c0. Report an issue: GitHub.