moeru-ai/airi · error · InvalidCharacterCardError
Invalid Character Card V3.
Error message
Invalid Character Card V3.
What it means
Thrown as InvalidCharacterCardError by parseCharacterCardV3() when valibot's safeParse against characterCardV3Schema fails. The schema enforces spec === 'chara_card_v3', a dotted spec_version, and a nested data object with required string fields; failure means the input is structurally not a CCv3 card. The error's cause carries the valibot issues and .source carries the original input.
Source
Thrown at packages/ccc/src/codec/characterCardV3.ts:179
/** Checks whether an error came from the CCv3 parsing boundary. */
export function isInvalidCharacterCardError(error: unknown): error is InvalidCharacterCardError {
return error instanceof InvalidCharacterCardError
}
/**
* Parses and validates a Character Card V3 object or JSON document.
*
* Unknown fields are preserved so a newer card can be inspected and exported
* without silently discarding data AIRI does not understand yet. Older and
* newer `spec_version` values are accepted and reported through
* `compatibility`; callers can decide how prominently to warn users.
*/
export function parseCharacterCardV3(source: unknown): ParsedCharacterCardV3 {
const candidate = parseJsonSource(source)
const result = safeParse(characterCardV3Schema, candidate)
if (!result.success) {
throw new InvalidCharacterCardError({
cause: result.issues,
source,
})
}
return {
card: result.output,
compatibility: resolveCompatibility(result.output.spec_version),
}
}
function parseJsonSource(source: unknown): unknown {
if (typeof source !== 'string')
return source
try {
return JSON.parse(source)
}View on GitHub (pinned to 27111382b4)
Solutions
- Inspect error.cause (valibot issues) to see the exact failing path and expected type.
- Upgrade V2 cards to V3: set spec='chara_card_v3', spec_version='3.0', and nest fields under data.
- If you must accept older cards, detect the version first and run the V2/V1 parser instead of parseCharacterCardV3.
- Validate with a JSON schema tool upstream and surface field-level errors to the user.
Example fix
// before
const parsed = parseCharacterCardV3(cardJsonV2) // { spec: 'chara_card_v2', name: ... }
// after
const v3 = { spec: 'chara_card_v3', spec_version: '3.0', data: { ...cardJsonV2, alternate_greetings: [], group_only_greetings: [], tags: [], ... } }
const parsed = parseCharacterCardV3(v3) Defensive patterns
Strategy: try-catch
Validate before calling
import { safeParse } from 'valibot'
// Validate shape upstream with the same schema exports if available, else a lightweight check:
function looksLikeV3(card: unknown): boolean {
return !!card && typeof card === 'object' && (card as any).spec === 'chara_card_v3' && !!(card as any).data
} Type guard
import { isInvalidCharacterCardError } from '@proj-airi/ccc'
// isInvalidCharacterCardError narrows the thrown error type after catch
function isCardLike(v: unknown): v is { spec: unknown; data: unknown } {
return !!v && typeof v === 'object' && 'spec' in v && 'data' in v
} Try / catch
import { isInvalidCharacterCardError, parseCharacterCardV3 } from '@proj-airi/ccc'
try {
const parsed = parseCharacterCardV3(input)
} catch (error) {
if (isInvalidCharacterCardError(error)) {
console.error('Card rejected. Issues:', error.cause)
// surface error.cause (valibot issues) to the user
}
throw error
} Prevention
- Use isInvalidCharacterCardError() to branch on parse failures distinctly.
- Detect the spec version before choosing V1/V2/V3 parser.
- Show error.cause (valibot issues) to users for actionable field-level fixes.
When it happens
Trigger: Passing an object or JSON string that is missing required fields (e.g. no data.name, data.first_mes), has spec set to 'chara_card_v2', uses wrong types (alternate_greetings not a string array), or a spec_version that does not match /^\d+(?:\.\d+)*$/.
Common situations: Loading a Character Card V2 file into a V3-only parser; user-uploaded card missing required fields; hand-edited JSON with a typo in spec or spec_version; a card exported by a tool that omits empty strings; downstream code that assumes any JSON object is a valid card.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid Godot stage scene input payload.
- Expected `cap run --list --json` to return a JSON array.
- CAP_VITE_CAP_ARGS_JSON must be a JSON string array.
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/4fe09063add39858.
Report an issue: GitHub.