{"record":{"id":"dda863e122a6e703","repo":"moeru-ai/airi","slug":"the-file-does-not-contain-valid-json","errorCode":null,"errorMessage":"The file does not contain valid JSON.","messagePattern":"The file does not contain valid JSON\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts","lineNumber":447,"sourceCode":"): Live2DMotionKeyframe[] {\n  return points\n    .map(point => point.id === id ? { ...point, atMs, value } : point)\n    .sort((left, right) => left.atMs - right.atMs)\n}\n\n/** Serializes a motion project with its source recording and overlays. */\nexport function stringifyLive2DMotionProject(project: Live2DMotionProject): string {\n  return `${JSON.stringify(project, null, 2)}\\n`\n}\n\n/** Parses a motion project file and checks its structural and timeline invariants. */\nexport function parseLive2DMotionProject(raw: string): Live2DMotionProject {\n  let input: unknown\n  try {\n    input = JSON.parse(raw)\n  }\n  catch {\n    throw new Error('The file does not contain valid JSON.')\n  }\n\n  const result = safeParse(motionProjectSchema, input)\n  if (!result.success)\n    throw new Error('The file is not an AIRI Live2D motion project.')\n\n  const project = result.output\n  if (project.source.durationMs !== project.durationMs)\n    throw new Error('The motion project source is invalid.')\n\n  if (project.source.samples[0].atMs !== 0 || project.source.samples.at(-1)!.atMs > project.durationMs)\n    throw new Error('The motion project source timeline is invalid.')\n  for (let index = 1; index < project.source.samples.length; index++) {\n    if (project.source.samples[index].atMs < project.source.samples[index - 1].atMs)\n      throw new Error('The motion project source samples are not in time order.')\n  }\n\n  for (const overlay of project.overlays) {","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/stage-ui/src/features/devtools/motion/live2d/composables/keyframes.ts#L429-L465","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst raw = await file.arrayBuffer().then(b => String(b)) // binary garbage\nparseLive2DMotionProject(raw)\n// after\nconst raw = await file.text()\ntry {\n  const project = parseLive2DMotionProject(raw)\n}\ncatch (error) {\n  if (error.message === 'The file does not contain valid JSON.')\n    showError('Selected file is not JSON. Please choose an exported .json motion project.')\n}","handlingStrategy":"validation","validationCode":"function isParseableJson(raw) {\n  if (typeof raw !== 'string' || raw.trim() === '')\n    return false\n  try {\n    JSON.parse(raw)\n    return true\n  }\n  catch {\n    return false\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const project = parseLive2DMotionProject(raw)\n}\ncatch (error) {\n  switch (error.message) {\n    case 'The file does not contain valid JSON.':\n      notifyUser('This file is not valid JSON. Please select an exported AIRI motion project (.json).')\n      break\n    default: throw error\n  }\n}","preventionTips":["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."],"tags":["json","parsing","validation","live2d"],"backgroundTag":"invalid-json","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":"2026-09-02T04:27:24.639Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}