{"record":{"id":"842a3a85c855b889","repo":"laurent22/joplin","slug":"could-not-find-extra-script-name-at-fullp","errorCode":null,"errorMessage":"Could not find extra script: \"${name}\" at \"${fullPath}\"","messagePattern":"Could not find extra script: \"(.+?)\" at \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/generator-joplin/generators/app/templates/webpack.config.js","lineNumber":286,"sourceCode":"\tresolve: {\n\t\tfallback: moduleFallback,\n\t},\n\toutput: {\n\t\tfilename: 'index.js',\n\t\tpath: publishDir,\n\t},\n\tplugins: [{\n\t\tapply(compiler) {\n\t\t\tcompiler.hooks.done.tap('archiveOnBuildListener', onBuildCompleted);\n\t\t},\n\t}],\n};\n\nfunction resolveExtraScriptPath(name) {\n\tconst relativePath = `./src/${name}`;\n\n\tconst fullPath = path.resolve(`${rootDir}/${relativePath}`);\n\tif (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: \"${name}\" at \"${fullPath}\"`);\n\n\tconst s = name.split('.');\n\ts.pop();\n\tconst nameNoExt = s.join('.');\n\n\treturn {\n\t\tentry: relativePath,\n\t\toutput: {\n\t\t\tfilename: `${nameNoExt}.js`,\n\t\t\tpath: distDir,\n\t\t\tlibrary: 'default',\n\t\t\tlibraryTarget: 'commonjs',\n\t\t\tlibraryExport: 'default',\n\t\t},\n\t};\n}\n\nfunction buildExtraScriptConfigs(userConfig) {","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/generator-joplin/generators/app/templates/webpack.config.js#L268-L304","documentation":"Thrown by resolveExtraScriptPath() for each extra script declared in plugin.config.json. The script must exist at `./src/${name}` relative to rootDir. fs.pathExistsSync returning false aborts before webpack entry config is built.","triggerScenarios":"plugin.config.json lists an extra script (e.g. \"markdownItTestPlugin.js\") and the file is absent from src/, misnamed, or in a different directory.","commonSituations":"Author edited plugin.config.json but did not create the matching file; filename casing differs on case-sensitive filesystems; file was moved to a subfolder.","solutions":["Read the error — it prints both `name` and the resolved `fullPath`; create the file at that exact path.","Verify filename casing matches exactly (src/Foo.js vs src/foo.js).","If the entry in plugin.config.json is wrong, correct or remove it.","Re-run the build."],"exampleFix":"// plugin.config.json (before)\n{ \"extraScriptOptions\": { \"markdownItTestPlugin.js\": {} } }\n// src/ has markdownItPlugin.js (typo)\n// after: create src/markdownItTestPlugin.js OR fix the name in plugin.config.json","handlingStrategy":"validation","validationCode":"const fs = require('fs-extra');\nconst path = require('path');\nfor (const name of Object.keys(pluginConfig.extraScriptOptions || {})) {\n  const full = path.resolve(rootDir, 'src', name);\n  if (!fs.pathExistsSync(full)) throw new Error(`Missing extra script file: ${full}`);\n}","typeGuard":"const extraScriptExists = (name, rootDir) => fs.pathExistsSync(path.resolve(rootDir, 'src', name));","tryCatchPattern":"try { resolveExtraScriptPath(name); }\ncatch (e) { if (/Could not find extra script/.test(e.message)) { /* create file or fix plugin.config.json */ } else throw e; }","preventionTips":["Keep plugin.config.json's extraScriptOptions keys in sync with files in src/ via a pre-build check.","On case-sensitive filesystems, treat filename casing as significant and lint against mismatches."],"tags":["plugin-build","extra-scripts","generator-joplin"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}