can1357/oh-my-pi · error · AIError.ValidationError
Missing `context` object
Error message
Missing `context` object
What it means
parseRequest validates the JSON body of a request to the pi-native server before streaming. It requires a `context` object holding the conversation (messages, optional systemPrompt/tools). If `context` is absent, not an object, null, or an array, the server rejects the request with this ValidationError so callers get a clear 400-style signal instead of a downstream crash.
Source
Thrown at packages/ai/src/providers/pi-native-server.ts:121
if (typeof body !== "object" || body === null || Array.isArray(body)) {
throw new AIError.ValidationError("Request body must be a JSON object");
}
const obj = body as Record<string, unknown>;
let modelId: string | undefined;
if (typeof obj.modelId === "string" && obj.modelId.length > 0) {
modelId = obj.modelId;
} else if (typeof obj.model === "string" && obj.model.length > 0) {
modelId = obj.model;
} else if (typeof obj.model === "object" && obj.model !== null) {
const m = obj.model as Record<string, unknown>;
if (typeof m.id === "string" && m.id.length > 0) modelId = m.id;
}
if (!modelId) throw new AIError.ValidationError("Missing `modelId` (or `model.id`) field");
const context = obj.context;
if (typeof context !== "object" || context === null || Array.isArray(context)) {
throw new AIError.ValidationError("Missing `context` object");
}
const ctxObj = context as Record<string, unknown>;
if (!Array.isArray(ctxObj.messages)) {
throw new AIError.ValidationError("`context.messages` must be an array");
}
if (ctxObj.systemPrompt !== undefined && !Array.isArray(ctxObj.systemPrompt)) {
throw new AIError.ValidationError("`context.systemPrompt` must be an array of strings when present");
}
if (ctxObj.tools !== undefined && !Array.isArray(ctxObj.tools)) {
throw new AIError.ValidationError("`context.tools` must be an array when present");
}
const options: SimpleStreamOptions = {};
const rawOpts = obj.options;
if (typeof rawOpts === "object" && rawOpts !== null && !Array.isArray(rawOpts)) {
const optsBag = options as Record<string, unknown>;
for (const [k, v] of Object.entries(rawOpts)) {
if (v === undefined || v === null) continue;View on GitHub (pinned to 9690622007)
Solutions
- Add a `context` object to the request body containing at least `messages` as an array
- If migrating from an older schema, move top-level `messages`/`systemPrompt`/`tools` inside `context`
- Check that the client is actually sending a parsed JSON object, not a JSON-encoded string as the body
Example fix
// before
{"model":{"id":"qwen3.5-plus"},"messages":[{"role":"user","content":"hi"}]}
// after
{"model":{"id":"qwen3.5-plus"},"context":{"messages":[{"role":"user","content":"hi"}]}} Defensive patterns
Strategy: validation
Validate before calling
if (!body || typeof body !== 'object' || Array.isArray(body) || !body.context || typeof body.context !== 'object' || Array.isArray(body.context)) throw new Error('body.context object required'); Type guard
function hasContextObject(b: unknown): b is { context: Record<string, unknown> } {
return typeof b === 'object' && b !== null && !Array.isArray(b) && typeof (b as { context?: unknown }).context === 'object' && (b as { context: unknown }).context !== null && !Array.isArray((b as { context: unknown }).context);
} Try / catch
try { const req = parseRequest(body); } catch (e) { if (e instanceof AIError.ValidationError && String(e.message).includes('`context` object')) return respond400('request body must contain a context object'); throw e; } Prevention
- Keep a typed request-builder that always constructs {model, context:{messages,...}}
- Unit-test the payload serializer against the server schema
- Assert the body parses to an object (not a double-encoded string) before sending
When it happens
Trigger: POSTing a JSON body to the pi-native server endpoint whose top-level object lacks `context`, sets it to null, sets it to a string/number, or sends it as an array (e.g. `{"model":{"id":"..."}}` with no context key).
Common situations: Hand-written curl/httpie calls omitting the context wrapper; clients built against an older request schema that passed messages at the top level; JSON body accidentally stringified so `context` arrives as a string; proxies rewriting the body.
Related errors
- `context.messages` must be an array
- `context.systemPrompt` must be an array of strings when pres
- `context.tools` must be an array when present
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/52dfc08bfd49d6ca.
Report an issue: GitHub.