moeru-ai/airi · error · Error
Invalid Godot stage view-state patch payload.
Error message
Invalid Godot stage view-state patch payload.
What it means
Thrown by parseStageViewPatchPayload when the incoming payload fails safeParse against StageViewPatchSchema. The schema is a strictObject that allows only an optional `camera` (StageCameraPosePatchSchema), and a check() requires at least one field to be present — so an empty object {}, unknown keys, non-object payloads, or a malformed camera pose all fail. It guards the host-origin boundary of the Godot stage view-state protocol.
Source
Thrown at packages/stage-shared/src/godot-stage/view-state.ts:97
function hasStageViewPatchMutation(patch: StageViewPatch) {
return hasStageViewVec3PatchMutation(patch.camera?.position)
|| patch.camera?.yawDeg !== undefined
|| patch.camera?.pitchDeg !== undefined
|| patch.camera?.fovDeg !== undefined
}
export const StageViewPatchSchema = pipe(
strictObject({
camera: optional(StageCameraPosePatchSchema),
}),
check(hasStageViewPatchMutation, 'View patch must include at least one field.'),
)
/** Parses a host-origin Godot view-state patch. */
export function parseStageViewPatchPayload(payload: unknown): StageViewPatch {
const result = safeParse(StageViewPatchSchema, payload)
if (!result.success)
throw new Error('Invalid Godot stage view-state patch payload.')
return result.output
}
/** Reason attached to a Godot view-state snapshot event. */
export type StageViewSnapshotReason
= | 'loaded'
| 'remote-patch'
| 'local-input'
| 'request'
| 'shutdown-flush'
/** Runtime-only avatar bounds emitted with view snapshots for UI range decisions. */
export interface StageAvatarBoundsPayload {
center: StageViewVec3
size: StageViewVec3
maxDimension: number
}View on GitHub (pinned to 677329427f)
Solutions
- Log the safeParse issues next to the generic error: const r = safeParse(StageViewPatchSchema, payload); if (!r.success) report r.issues — the issues pinpoint the offending field
- Ensure the payload is a parsed object of shape { camera: { ...StageCameraPosePatch fields } } and contains no extra top-level keys
- Align versions of packages/stage-shared between the host and the Godot stage process after protocol changes
- Reproduce the exact wire payload in a unit test and iterate until safeParse succeeds before touching integration code
Example fix
// before
const patch = parseStageViewPatchPayload(raw) // opaque 'Invalid ... patch payload.'
// after
import { safeParse, StageViewPatchSchema, parseStageViewPatchPayload } from '../godot-stage/view-state'
const checked = safeParse(StageViewPatchSchema, raw)
if (!checked.success) {
throw new Error(`View patch rejected: ${JSON.stringify(checked.issues.map(i => [i.path, i.message]))}`)
}
const patch = parseStageViewPatchPayload(raw) Defensive patterns
Strategy: validation
Validate before calling
import { safeParse, StageViewPatchSchema } from '../godot-stage/view-state'
const checked = safeParse(StageViewPatchSchema, payload)
if (!checked.success) {
log.warn('view patch rejected', checked.issues)
return
}
const patch = parseStageViewPatchPayload(payload) Type guard
const isStageViewPatchInput = (p: unknown): boolean => safeParse(StageViewPatchSchema, p).success
Try / catch
catch (e) { if (e.message.includes('view-state patch payload')) { log.warn('dropping malformed patch', payload); return } throw e } Prevention
- Always safeParse external payloads first and log r.issues for the exact path
- Keep packages/stage-shared and the Godot plugin versions locked together
- Add a Vitest fixture of the real wire payload to catch protocol drift
When it happens
Trigger: Sending {}, null, a JSON string (not yet parsed), an object with typo'd keys like {"cameraa": {...}}, or a camera patch missing required pose fields to the patch ingestion path that calls parseStageViewPatchPayload.
Common situations: Version skew between the host package and the Godot plugin where one side adds/renames fields; hand-crafting IPC or HTTP payloads in tests without consulting the schema; double-encoding the payload (JSON.stringify twice) so it arrives as a string; forwarding a snapshot payload where a patch was expected.
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
- Invalid Godot stage view-state snapshot payload.
- Invalid Godot stage view-state error payload.
- Invalid Character Card V3.
- Invalid WebSocket event format.
- Invalid AIRI websocket message.
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/e281d285b5ff6486.
Report an issue: GitHub.