farion1231/cc-switch · error · PiFormValidationError
Thinking levels may only use Pi's native keys, with string o
Error message
Thinking levels may only use Pi's native keys, with string or null values.
What it means
PiProviderForm validates the per-model thinking-level map with isPiThinkingLevelMap() when the row carries one (model.hasThinkingLevelMap); on failure it throws pi.form.thinkingLevelMapInvalid focusing #pi-model-thinking-levels-<rowKey> with revealAdvanced. Pi's native schema only accepts its own thinking-level keys mapped to string or null values (e.g. levels like 'high'/'medium'/'off' style names), so free-form objects, numbers, booleans, or arrays are rejected to keep the generated settings file schema-valid.
Source
Thrown at src/components/providers/forms/PiProviderForm.tsx:1160
label: t("pi.form.contextWindow"),
}),
`#pi-model-context-window-${model.key}`,
)
: undefined;
const maxTokens = includeMaxTokens
? positiveNumber(
model.maxTokens,
t("pi.form.positiveNumberRequired", {
label: t("pi.form.maxTokens"),
}),
`#pi-model-max-tokens-${model.key}`,
)
: undefined;
if (
model.hasThinkingLevelMap &&
!isPiThinkingLevelMap(model.thinkingLevelMap)
) {
throw new PiFormValidationError(
t("pi.form.thinkingLevelMapInvalid"),
`#pi-model-thinking-levels-${model.key}`,
true,
);
}
// Pi's schema supports rare per-model api/baseUrl overrides. Keep
// imported values losslessly, but use the provider-level format and
// endpoint as the normal product model.
const modelApi =
typeof model.passthrough.api === "string"
? model.passthrough.api.trim()
: "";
const modelBaseUrl =
typeof model.passthrough.baseUrl === "string"
? model.passthrough.baseUrl.trim()
: "";
// Existing explicit nodes may be partial overrides of a Pi built-in
// provider. Pi inherits the built-in transport in that case, so onlyView on GitHub (pinned to 0b5da51016)
Solutions
- Rewrite the map to use Pi's native thinking-level keys with string or null values, e.g. { "default": "high", "off": null }-shaped entries per Pi's documented schema.
- Remove the thinking-level override entirely if you do not need it — the field is optional (hasThinkingLevelMap false rows skip validation).
- Check Pi's provider schema/docs for the exact allowed key set for your provider version before hand-writing the map.
Example fix
// before
thinkingLevelMap = { high: 3, medium: 2 }; // numeric values -> throws
// or
thinkingLevelMap = { "deep-think": "on" }; // non-native key -> throws
// after
thinkingLevelMap = { high: "high", medium: "medium", low: null }; // string|null values on native keys Defensive patterns
Strategy: type-guard
Validate before calling
import { isPiThinkingLevelMap } from "./piSchema"; // same helper the form uses
if (model.hasThinkingLevelMap && !isPiThinkingLevelMap(model.thinkingLevelMap)) {
showEditorError("Thinking levels: native keys only, string or null values");
} Type guard
function isPiThinkingLevelMap(v: unknown): v is Record<string, string | null> {
if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
return Object.values(v).every((x) => x === null || typeof x === "string");
} Try / catch
catch (e) {
if (e instanceof PiFormValidationError) { setAdvancedOpen(true); setFormError(e.message); return; }
throw e;
} Prevention
- Offer a dropdown of Pi's documented thinking-level keys instead of free-text JSON.
- Validate the map on change and block saving while invalid.
When it happens
Trigger: Hand-editing the thinking levels JSON to use non-native keys (custom names like "deep-think"), values of wrong type (0/1/2, true, nested objects), or pasting a generic reasoning-effort config from another tool; only checked when the row actually has a thinkingLevelMap.
Common situations: Porting OpenAI-style reasoning_effort numbers or Anthropic budget_tokens into Pi's thinking map; typos in level keys; mixing formats when copying configs between providers.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- {{label}} must be an absolute HTTP or HTTPS URL
- {{label}} must be a number greater than 0
- Select a preset or custom configuration first
- Configuration must be a JSON object, not an array or other t
- Display name is required
AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20).
Data as JSON: /api/errors/7a9dbb490a32620f.
Report an issue: GitHub.