{"record":{"id":"6758fa8cef06f9ea","repo":"microsoft/TypeScript","slug":"expected-inputfile-to-be-a-file","errorCode":null,"errorMessage":"Expected ${inputFile} to be a file","messagePattern":"Expected (.+?) to be a file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/produceLKG.mjs","lineNumber":39,"sourceCode":"    await copyTypesMap();\r\n    await copyScriptOutputs();\r\n    await copyDeclarationOutputs();\r\n    await writeGitAttributes();\r\n}\r\n\r\nasync function copyLibFiles() {\r\n    await copyFilesWithGlob(\"lib?(.*).d.ts\");\r\n}\r\n\r\nasync function copyLocalizedDiagnostics() {\r\n    for (const d of localizationDirectories) {\r\n        const inputDir = path.join(source, d);\r\n        if (!fs.statSync(inputDir).isDirectory()) throw new Error(`Expected ${inputDir} to be a directory`);\r\n        const outputDir = path.join(dest, d);\r\n        await fs.promises.mkdir(outputDir, { recursive: true });\r\n        for (const f of await fs.promises.readdir(inputDir)) {\r\n            const inputFile = path.join(inputDir, f);\r\n            if (!fs.statSync(inputFile).isFile()) throw new Error(`Expected ${inputFile} to be a file`);\r\n            const outputFile = path.join(outputDir, f);\r\n            await fs.promises.copyFile(inputFile, outputFile);\r\n        }\r\n    }\r\n}\r\n\r\nasync function copyTypesMap() {\r\n    await copyFromBuiltLocal(\"typesMap.json\"); // Cannot accommodate copyright header\r\n}\r\n\r\nasync function copyScriptOutputs() {\r\n    await copyFromBuiltLocal(\"tsc.js\");\r\n    await copyFromBuiltLocal(\"_tsc.js\");\r\n    await copyFromBuiltLocal(\"tsserver.js\");\r\n    await copyFromBuiltLocal(\"_tsserver.js\");\r\n    await copyFromBuiltLocal(\"tsserverlibrary.js\");\r\n    await copyFromBuiltLocal(\"typescript.js\");\r\n    await copyFromBuiltLocal(\"typingsInstaller.js\");\r","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/microsoft/TypeScript/blob/b465fdbfe175304d9b977da137b2c178ae1091d3/scripts/produceLKG.mjs#L21-L57","documentation":"While copying a localization directory, produceLKG.mjs stats every entry returned by readdir and throws if an entry isn't a plain file, guarding against symlinks, subdirectories, or special files leaking into the LKG.","triggerScenarios":"An entry inside a localization source directory is a subdirectory, symlink, or other non-regular file.","commonSituations":"A build tool wrote a subdirectory or symlink into a localization output dir; leftover artifacts from a different toolchain.","solutions":["Inspect the inputFile path in the error and remove/flatten the offending entry.","Re-run the localization build into a clean directory.","Ensure no post-processing step creates nested dirs or symlinks under localization output."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import fs from \"fs\";\nfor (const f of await fs.promises.readdir(inputDir)) {\n  const p = path.join(inputDir, f);\n  if (!fs.statSync(p).isFile()) throw new Error(`Expected ${p} to be a file`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure localization tooling emits only regular files (no symlinks/subdirs).","Audit post-processing steps that might write nested entries."],"tags":["lkg","localization","build","validation"],"backgroundTag":null,"analyzedSha":"b465fdbfe175304d9b977da137b2c178ae1091d3","analyzedAt":"2026-08-12T05:38:42.698Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}