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

  1. 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
  2. Ensure the payload is a parsed object of shape { camera: { ...StageCameraPosePatch fields } } and contains no extra top-level keys
  3. Align versions of packages/stage-shared between the host and the Godot stage process after protocol changes
  4. 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

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


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/e281d285b5ff6486. Report an issue: GitHub.