{"record":{"id":"3090575c2e216dee","repo":"affaan-m/ECC","slug":"failed-to-read-path-basename-filepath-error","errorCode":null,"errorMessage":"Failed to read ${path.basename(filePath)}: ${error.message}","messagePattern":"Failed to read (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/ci/catalog.js","lineNumber":68,"sourceCode":"function buildCatalog(root = ROOT) {\n  const agents = listMatchingFiles(root, 'agents', entry => entry.isFile() && entry.name.endsWith('.md'));\n  const commands = listMatchingFiles(root, 'commands', entry => entry.isFile() && entry.name.endsWith('.md'));\n  const skills = listMatchingFiles(root, 'skills', entry => (\n    entry.isDirectory() && fs.existsSync(path.join(root, 'skills', entry.name, 'SKILL.md'))\n  )).map(skillDir => `${skillDir}/SKILL.md`);\n\n  return {\n    agents: { count: agents.length, files: agents, glob: 'agents/*.md' },\n    commands: { count: commands.length, files: commands, glob: 'commands/*.md' },\n    skills: { count: skills.length, files: skills, glob: 'skills/*/SKILL.md' }\n  };\n}\n\nfunction readFileOrThrow(filePath) {\n  try {\n    return fs.readFileSync(filePath, 'utf8');\n  } catch (error) {\n    throw new Error(`Failed to read ${path.basename(filePath)}: ${error.message}`);\n  }\n}\n\nfunction writeFileOrThrow(filePath, content) {\n  try {\n    fs.writeFileSync(filePath, content, 'utf8');\n  } catch (error) {\n    throw new Error(`Failed to write ${path.basename(filePath)}: ${error.message}`);\n  }\n}\n\nfunction replaceOrThrow(content, regex, replacer, source) {\n  if (!regex.test(content)) {\n    throw new Error(`${source} is missing the expected catalog marker`);\n  }\n\n  return content.replace(regex, replacer);\n}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/ci/catalog.js#L50-L86","documentation":"After fetching the remote URL, _fetch_import_url() inspects the Content-Type response header and only allows text-like types: anything containing 'text/', 'markdown', 'yaml', 'json', or 'octet-stream'. Any other content type is rejected to prevent importing binary, executable, or media payloads disguised as instinct files. An empty/missing Content-Type is allowed (treated as permissible).","triggerScenarios":"Server returns Content-Type: application/zip, image/png, application/x-executable, video/mp4, application/xml, or application/pdf for the instinct URL.","commonSituations":"The file is actually binary (uploaded by mistake); a CDN/proxy serves .md with a generic binary content type; the host applies a catch-all content type for unknown extensions; a misconfigured object store returns application/x-gzip.","solutions":["Ensure the host serves the file with a text-like Content-Type (text/plain, text/markdown, application/json, application/yaml, or application/octet-stream).","Verify the URL points to an actual text/markdown/yaml/json file and not a packaged binary.","If you control the server, set the correct Content-Type header for .md/.yaml/.json files."],"exampleFix":"# server-side fix (nginx)\n# before: default_type application/octet-stream;\n# after:\n# types { text/markdown md; application/yaml yaml; application/json json; }","handlingStrategy":"validation","validationCode":"# Optional: HEAD the URL first to check Content-Type before fetching.\nimport urllib.request\nreq = urllib.request.Request(url, method='HEAD')\nwith urllib.request.urlopen(req, timeout=15) as resp:\n    ct = resp.headers.get('Content-Type', '')\nallowed = ('text/', 'markdown', 'yaml', 'json', 'octet-stream')\nif ct and not any(a in ct.lower() for a in allowed):\n    raise SystemExit(f'unsupported content type {ct!r} — expected a text-like type')","typeGuard":"ALLOWED_CT = ('text/', 'markdown', 'yaml', 'json', 'octet-stream')\n\ndef content_type_allowed(ct: str) -> bool:\n    return not ct or any(a in ct.lower() for a in ALLOWED_CT)","tryCatchPattern":"try:\n    content = _fetch_import_url(source)\nexcept ValueError as e:\n    if 'content type' in str(e):\n        # surface to user: the host served a binary type for a text file\n        log.error('host served an unsupported content type — fix server headers or pick another URL')\n    raise","preventionTips":["Serve instinct files from a host that sets a correct text-like Content-Type.","Do not point the importer at binary archives, images, or executables.","If you control the server, configure explicit types for .md/.yaml/.json extensions."],"tags":["security","network","content-type","validation","import"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}