{"record":{"id":"cfe86c32a07e06dd","repo":"remotion-dev/remotion","slug":"path-must-be-an-object","errorCode":null,"errorMessage":"${path} must be an object.","messagePattern":"(.+?) must be an object\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio/src/components/parse-caption-file.ts","lineNumber":39,"sourceCode":"\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(contents);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error('Expected a Remotion Caption[] JSON array.');\n\t}\n\n\tlet previousStart: number | null = null;\n\tfor (const [index, caption] of parsed.entries()) {\n\t\tconst path = `captions[${index}]`;\n\t\tif (!isObject(caption)) {\n\t\t\tthrow new Error(`${path} must be an object.`);\n\t\t}\n\n\t\tif (typeof caption.text !== 'string') {\n\t\t\tthrow new Error(`${path}.text must be a string.`);\n\t\t}\n\n\t\tif (!isFiniteNumber(caption.startMs) || caption.startMs < 0) {\n\t\t\tthrow new Error(`${path}.startMs must be a finite, non-negative number.`);\n\t\t}\n\n\t\tif (!isFiniteNumber(caption.endMs) || caption.endMs < 0) {\n\t\t\tthrow new Error(`${path}.endMs must be a finite, non-negative number.`);\n\t\t}\n\n\t\tif (caption.endMs < caption.startMs) {\n\t\t\tthrow new Error(`${path}.endMs must not be earlier than startMs.`);\n\t\t}\n","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/studio/src/components/parse-caption-file.ts#L21-L57","documentation":"Each element of the top-level JSON array must be a Caption object. This error is thrown when an element is a non-object value (string, number, boolean, null, or a nested array). isObject explicitly rejects arrays and null.","triggerScenarios":"parseCaptionFile receives contents whose parsed array contains an element like \"hello\", 42, null, true, or [] at captions[i].","commonSituations":"A malformed export that flattens captions into mixed values; copy/paste corruption inserting a stray value between objects; manually writing [\"line one\", \"line two\"] instead of objects.","solutions":["Inspect element captions[i] in the JSON and replace it with a full caption object ({text, startMs, endMs, ...})","Re-export the caption file from the original tool in Remotion Caption JSON format","Validate each array element is an object before passing the file to the studio"],"exampleFix":"// before\n[\"hello world\"]\n// after\n[{\"text\": \"hello world\", \"startMs\": 0, \"endMs\": 2000, \"timestampMs\": null, \"confidence\": null}]","handlingStrategy":"validation","validationCode":"const arr: unknown[] = JSON.parse(contents);\narr.forEach((el, i) => {\n  if (typeof el !== 'object' || el === null || Array.isArray(el)) {\n    throw new Error(`captions[${i}] must be an object`);\n  }\n});","typeGuard":"const isCaptionObject = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try {\n  const captions = parseCaptionFile({fileName, contents});\n} catch (e) {\n  // message names captions[i]; fix that element and retry\n  console.error((e as Error).message);\n}","preventionTips":["Validate every array element is an object before import","Avoid hand-editing caption JSON; re-export from the source tool","Use an editor with JSON schema validation"],"tags":["json","validation","captions"],"backgroundTag":"schema-validation-failed","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}