{"record":{"id":"af4979cd5ad48bb9","repo":"davila7/claude-code-templates","slug":"failed-to-load-skill","errorCode":null,"errorMessage":"Failed to load skill","messagePattern":"Failed to load skill","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"cli-tool/src/skill-dashboard.js","lineNumber":392,"sourceCode":"      try {\n        await this.loadSkillsData();\n        const skillName = req.params.name;\n        const skill = this.skills.find(s =>\n          s.name === skillName ||\n          s.name.toLowerCase().replace(/\\s+/g, '-') === skillName.toLowerCase()\n        );\n\n        if (!skill) {\n          return res.status(404).json({ error: 'Skill not found' });\n        }\n\n        res.json({\n          skill,\n          timestamp: new Date().toISOString()\n        });\n      } catch (error) {\n        console.error('Error loading skill:', error);\n        res.status(500).json({ error: 'Failed to load skill' });\n      }\n    });\n\n    this.app.get('/api/skills/:name/file/*', async (req, res) => {\n      try {\n        const skillName = req.params.name;\n        const filePath = req.params[0]; // Capture the wildcard path\n\n        await this.loadSkillsData();\n        const skill = this.skills.find(s =>\n          s.name === skillName ||\n          s.name.toLowerCase().replace(/\\s+/g, '-') === skillName.toLowerCase()\n        );\n\n        if (!skill) {\n          return res.status(404).json({ error: 'Skill not found' });\n        }\n","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/davila7/claude-code-templates/blob/a0851ed10c7c60463dac8cfaaca124cf32d5804d/cli-tool/src/skill-dashboard.js#L374-L410","documentation":"HTTP 500 returned by the skill dashboard's GET /api/skills/:name/file/* route when reading a skill file throws an unexpected exception (the catch-all after 'Skill not found'/'Access denied'/'File not found' checks pass but fs.readFile/fs.stat fails). It signals an I/O or permission error outside the handled cases.","triggerScenarios":"GET /api/skills/<name>/file/<path> where the path passes the path-traversal check and exists, but reading fails: EACCES on a chmod-000 file, EISDIR, or the file is deleted between pathExists and readFile.","commonSituations":"Skill directory contains files with restrictive permissions, symlinks to unreadable targets, or race with an editor/process removing files while the dashboard is serving.","solutions":["Check dashboard server console for the logged 'Error loading file:' cause","Fix file/directory permissions (chmod) on the skill folder","Remove broken symlinks or special files from the skill directory","Retry after ensuring the file still exists"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const ok = await fetch(`/api/skills/${slug}/file/${encodeURIComponent(rel)}`).then(r => r.ok);","typeGuard":null,"tryCatchPattern":"try { const r = await fetch(url); if (!r.ok) throw new Error((await r.json()).error); } catch (e) { console.warn('skill file load failed', e); }","preventionTips":["Check /api/skills listing before requesting files","Keep skill files readable by the dashboard process"],"tags":["http-500","skill-dashboard","filesystem","express"],"backgroundTag":"file-read-permission-denied","analyzedSha":"a0851ed10c7c60463dac8cfaaca124cf32d5804d","analyzedAt":"2026-08-28T14:11:56.058Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}