{"record":{"id":"bfa0d97806aa9db3","repo":"remotion-dev/remotion","slug":"src-must-be-a-string-when-using-nodereader","errorCode":null,"errorMessage":"src must be a string when using `nodeReader`","messagePattern":"src must be a string when using `nodeReader`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/readers/from-node.ts","lineNumber":16,"sourceCode":"import {createReadStream, existsSync, promises, statSync} from 'fs';\nimport {dirname, join, relative, sep} from 'path';\nimport type {\n\tCreateAdjacentFileSource,\n\tMediaParserReaderInterface,\n\tReadContent,\n\tReadWholeAsText,\n} from './reader';\n\nexport const nodeReadContent: ReadContent = async ({\n\tsrc,\n\trange,\n\tcontroller,\n}) => {\n\tif (typeof src !== 'string') {\n\t\tthrow new Error('src must be a string when using `nodeReader`');\n\t}\n\n\tawait Promise.resolve();\n\n\tconst ownController = new AbortController();\n\n\ttry {\n\t\tif (!existsSync(src)) {\n\t\t\tthrow new Error(`File does not exist: ${src}`);\n\t\t}\n\n\t\tconst stream = createReadStream(src, {\n\t\t\tstart: range === null ? 0 : typeof range === 'number' ? range : range[0],\n\t\t\tend:\n\t\t\t\trange === null\n\t\t\t\t\t? Infinity\n\t\t\t\t\t: typeof range === 'number'\n\t\t\t\t\t\t? Infinity","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/readers/from-node.ts#L1-L34","documentation":"Thrown by nodeReadContent when the src passed to the Node.js filesystem reader is not a string. The Node reader uses fs.createReadStream and fs.existsSync, both of which require a filesystem path string. URL objects, Blobs, or File instances are not supported by nodeReader.","triggerScenarios":"Calling parseMedia with srcType 'node' (or nodeReader explicitly) while passing a URL object, Blob, or File as src instead of a filesystem path string. This trips before any filesystem access is attempted.","commonSituations":"Sharing a src value between a browser (URL/File) and a Node SSR/render context without normalizing it. Receiving a file:// URL object from another API and passing it straight to the Node reader. Accidentally selecting nodeReader in an Electron/browser environment.","solutions":["Pass a filesystem path string to nodeReader, e.g. '/abs/path/media.mp4' or a relative path resolved from process.cwd().","If you have a URL, convert it first: for file:// URLs use url.fileURLToPath(url); for http URLs switch to fetchReader.","If you have a Blob/File in Node, write it to a temp file and pass the path, or use a reader that accepts streams."],"exampleFix":"// before\nawait parseMedia({ src: new URL('file:///tmp/a.mp4'), fields: {...} }); // node reader\n\n// after\nimport { fileURLToPath } from 'node:url';\nawait parseMedia({ src: fileURLToPath('file:///tmp/a.mp4'), fields: {...} });","handlingStrategy":"validation","validationCode":"function assertNodePath(src: unknown): asserts src is string {\n  if (typeof src !== 'string') throw new TypeError('nodeReader requires a filesystem path string');\n}\nassertNodePath(src);","typeGuard":"const isNodePath = (s: unknown): s is string => typeof s === 'string' && !s.startsWith('http');","tryCatchPattern":"try { await parseMedia({ src, srcType: 'node', fields }); } catch (e) { if (/src must be a string when using `nodeReader`/.test(String((e as Error).message))) { src = fileURLToPath(src); /* retry */ } else throw e; }","preventionTips":["Normalize URL/File inputs to path strings at the boundary of your Node code.","Use fileURLToPath for file:// URLs before passing to nodeReader.","Keep one helper that decides node vs fetch reader based on src type."],"tags":["media-parser","reader","node","filesystem","type-validation"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}