moeru-ai/airi · error · Error
The file does not contain valid JSON.
Error message
The file does not contain valid JSON.
What it means
parseLive2DMotionProject first attempts JSON.parse on the raw file contents. If the string is not syntactically valid JSON, it throws this error instead of leaking the native SyntaxError, signaling that the imported file is not parseable JSON at all. Validation of the parsed shape happens afterwards with motionProjectSchema.
Source
Thrown at packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts:447
): Live2DMotionKeyframe[] {
return points
.map(point => point.id === id ? { ...point, atMs, value } : point)
.sort((left, right) => left.atMs - right.atMs)
}
/** Serializes a motion project with its source recording and overlays. */
export function stringifyLive2DMotionProject(project: Live2DMotionProject): string {
return `${JSON.stringify(project, null, 2)}\n`
}
/** Parses a motion project file and checks its structural and timeline invariants. */
export function parseLive2DMotionProject(raw: string): Live2DMotionProject {
let input: unknown
try {
input = JSON.parse(raw)
}
catch {
throw new Error('The file does not contain valid JSON.')
}
const result = safeParse(motionProjectSchema, input)
if (!result.success)
throw new Error('The file is not an AIRI Live2D motion project.')
const project = result.output
if (project.source.durationMs !== project.durationMs)
throw new Error('The motion project source is invalid.')
if (project.source.samples[0].atMs !== 0 || project.source.samples.at(-1)!.atMs > project.durationMs)
throw new Error('The motion project source timeline is invalid.')
for (let index = 1; index < project.source.samples.length; index++) {
if (project.source.samples[index].atMs < project.source.samples[index - 1].atMs)
throw new Error('The motion project source samples are not in time order.')
}
for (const overlay of project.overlays) {View on GitHub (pinned to 9c213115f8)
Solutions
- Validate the file content with JSON.parse in a try/catch or a JSON linter to find the syntax error location.
- Check the file is not empty or truncated; re-export the motion project.
- Ensure the file is read as UTF-8 text (e.g. File.text() or readFileSync(path, 'utf8')) and strip any BOM.
- Confirm the user selected the correct .json motion project file, not an asset or archive.
Example fix
// before
const raw = await file.arrayBuffer().then(b => String(b)) // binary garbage
parseLive2DMotionProject(raw)
// after
const raw = await file.text()
try {
const project = parseLive2DMotionProject(raw)
}
catch (error) {
if (error.message === 'The file does not contain valid JSON.')
showError('Selected file is not JSON. Please choose an exported .json motion project.')
} Defensive patterns
Strategy: validation
Validate before calling
function isParseableJson(raw) {
if (typeof raw !== 'string' || raw.trim() === '')
return false
try {
JSON.parse(raw)
return true
}
catch {
return false
}
} Try / catch
try {
const project = parseLive2DMotionProject(raw)
}
catch (error) {
switch (error.message) {
case 'The file does not contain valid JSON.':
notifyUser('This file is not valid JSON. Please select an exported AIRI motion project (.json).')
break
default: throw error
}
} Prevention
- Read files as UTF-8 text (file.text()) and strip BOM before parsing.
- Check file extension and non-zero, non-binary content before import attempts.
- Show a JSON preview or file-size sanity check in the import UI.
- Do not append trailing commas or comments when hand-editing project files.
When it happens
Trigger: Calling parseLive2DMotionProject(raw) where raw is an empty string, truncated file content, a binary file, a file with a BOM or trailing garbage, or content in another format (YAML, XML) that is not valid JSON.
Common situations: User picks the wrong file in an import dialog (e.g. a .zip or .png); the project file was saved half-written due to a crash; file was edited by hand and syntax broke; reading a file with encoding issues introducing invalid characters.
Related errors
- Expected `cap run --list --json` to return a JSON array.
- Invalid chat session export format
- The MAGIC frame must contain ${poseAxes.length} Live2D value
- Archive entry not found: ${filePath}
- Expected a JSON object in ${filePath}
AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02).
Data as JSON: /api/errors/dda863e122a6e703.
Report an issue: GitHub.