JuliusBrussee/caveman · error · Error
Qwen routed profile is missing ${key}
Error message
Qwen routed profile is missing ${key} What it means
After merging the rendered profile overlay into Qwen's base config, the CLI asserts that the overlay itself defines both modelProviders and providerProtocol, because Qwen treats these as whole-object REPLACE settings — deep-merging would leave sibling providers selectable at runtime outside the /w/qwen route. If either key is absent from the overlay (a broken/trimmed profile template or an overlay builder that didn't emit it), this invariant throws.
Source
Thrown at packages/cli/src/index.ts:8878
// whenever native registration + journal + effective policy do not agree.
const configured = jsonValueAt(baseConfig, ["mcp", "excluded"]);
const preserved = Array.isArray(configured)
? configured.filter((item): item is string => typeof item === "string")
: [];
rawOverlay = deepMerge(rawOverlay, {
mcp: { excluded: [...new Set([...preserved, "caveman"])] },
});
}
}
const overlay = (mcpMode === "auto" ? rawOverlay : withoutCavemanMcpServer(rawOverlay as JsonObject)) as JsonObject;
const merged = deepMerge(baseConfig, overlay) as JsonObject;
if (agent.id === "qwen") {
// Qwen treats these as whole-object REPLACE settings. Our generic merge is
// intentionally conservative for other agents, but retaining a sibling
// provider here would make it selectable at runtime outside /w/qwen.
for (const key of ["modelProviders", "providerProtocol"] as const) {
const value = overlay[key];
if (value === undefined) throw new Error(`Qwen routed profile is missing ${key}`);
merged[key] = cloneJsonValue(value);
}
}
const rendered = JSON.stringify(merged, null, 2);
if (rendered === undefined) throw new Error("merged config is not JSON");
const outDir = mkdtempSync(join(tmpdir(), "caveman-wrap-"));
const outPath = join(outDir, `${agent.id}.json`);
writeFileSync(outPath, rendered + "\n", { mode: 0o600 });
wrapTempDirs.add(outDir);
env[inj.env_var] = outPath;
}
function cleanupWrapTempDirs() {
for (const dir of [...wrapTempDirs]) {
try {
rmSync(dir, { recursive: true, force: true });
} catch {
// Temp cleanup is best-effort; wrap must never fail after child exit.View on GitHub (pinned to 5184b3d11a)
Solutions
- Update the caveman CLI to the latest version so the bundled Qwen overlay templates match the installed profile schema.
- Re-fetch/re-sync your project profiles (`caveman sync`) so the managed/local config_overlay templates are complete.
- If you maintain a custom overlay builder for qwen, ensure it always emits both modelProviders and providerProtocol as whole objects.
- Inspect the rendered overlay (temporary settings written under a `caveman-wrap-*` temp dir) to confirm which key is missing and fix the source template.
Example fix
// before: custom qwen overlay missing replace-keys
{ model: { primary: "caveman/qwen3-coder" } }
// after: both REPLACE settings present
{ model: { primary: "caveman/qwen3-coder" }, modelProviders: { ... }, providerProtocol: "openai-completions" } Defensive patterns
Strategy: validation
Validate before calling
// Validate the qwen overlay before relying on it
const overlay = profile.config_overlay.managed ?? profile.config_overlay.local;
for (const key of ["modelProviders", "providerProtocol"]) {
if (overlay?.[key] === undefined) throw new Error(`qwen profile overlay missing ${key}; re-sync profiles`);
} Type guard
function qwenOverlayIsComplete(o: unknown): o is { modelProviders: object; providerProtocol: string } & Record<string, unknown> {
return typeof o === "object" && o !== null
&& (o as any).modelProviders !== undefined
&& (o as any).providerProtocol !== undefined;
} Try / catch
try {
execSync("caveman qwen", { stdio: "inherit" });
} catch (e) {
if (e instanceof Error && e.message.startsWith("Qwen routed profile is missing")) {
console.error("Profile overlay incomplete — run `caveman sync` or upgrade the CLI.");
process.exit(1);
}
throw e;
} Prevention
- Keep the CLI and synced profiles on matching versions (`caveman sync` after upgrades).
- Don't hand-edit managed profile overlay templates.
- If you supply a custom qwen overlay builder, add a test asserting both REPLACE keys are present.
- Diff your local profile JSON against a fresh download when this error appears after edits.
When it happens
Trigger: Running `caveman wrap qwen` (config-file injection path) where the rendered overlay object lacks `modelProviders` or `providerProtocol` — e.g. a managed/local profile template from the registry is missing these keys, an overlay builder produced a partial overlay, or a corrupted/customized profile JSON dropped them.
Common situations: Outdated CLI talking to a newer control plane whose profile overlay schema changed (or vice versa); locally edited or partially synced profile templates; custom builds where overlayBuilders.qwen was replaced with a thinner overlay.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- invalid Decision Ledger response
- cannot safely resolve Qwen's effective settings
- cave_stale_lock:${checked.stale.join(",")}: run npm run buil
- cave_live_eval_sandbox_profile_invalid
- cave_transform_trace_basis_mixed
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-09-06).
Data as JSON: /api/errors/7f00687bf467f4c5.
Report an issue: GitHub.