{"record":{"id":"149a7bc8b0e1f0e7","repo":"can1357/oh-my-pi","slug":"security-knowledge-base-is-not-a-file-input","errorCode":null,"errorMessage":"Security knowledge base is not a file: ${input}","messagePattern":"Security knowledge base is not a file: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/preflight.ts","lineNumber":235,"sourceCode":"\t\trepositoryRoot,\n\t\tdisplayName,\n\t\tincludePaths,\n\t\texcludePaths,\n\t\ttreeDigest: await digestWorkingTree(repositoryRoot, includePaths, excludePaths, adapter, signal),\n\t};\n\tif (revision !== null) target.revision = revision;\n\treturn target;\n}\n\nasync function normalizeKnowledgeBases(\n\tpaths: readonly string[] | undefined,\n\tbaseDirectory: string,\n): Promise<SecurityKnowledgeBaseRef[]> {\n\tconst results: SecurityKnowledgeBaseRef[] = [];\n\tfor (const input of paths ?? []) {\n\t\tconst canonical = await fs.realpath(path.resolve(baseDirectory, input));\n\t\tconst stats = await fs.stat(canonical);\n\t\tif (!stats.isFile()) throw new Error(`Security knowledge base is not a file: ${input}`);\n\t\tconst digest = await hashFile(canonical);\n\t\tresults.push({ path: canonical, sha256: digest.sha256, size: digest.size });\n\t}\n\treturn results.sort((left, right) => left.path.localeCompare(right.path));\n}\n\nasync function normalizeOutput(\n\trepositoryRoot: string,\n\toutputRoot: string,\n\tarchiveExisting: boolean,\n): Promise<SecurityOutputPlan> {\n\tconst requested = path.resolve(outputRoot);\n\tconst parent = await fs.realpath(path.dirname(requested));\n\tconst canonicalCandidate = path.join(parent, path.basename(requested));\n\tif (pathIsWithin(canonicalCandidate, repositoryRoot)) {\n\t\tthrow new Error(\"Security output directory must be outside the scanned repository\");\n\t}\n\tlet existingState: SecurityOutputPlan[\"existingState\"] = \"absent\";","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/preflight.ts#L217-L253","documentation":"normalizeKnowledgeBases validates each configured security knowledge base path before a security preflight scan. Each input is resolved against baseDirectory, canonicalized with fs.realpath, and stat-ed; if the resulting entry is not a regular file (directory, symlink to dir, socket, etc.), the function refuses to proceed. This guarantees every knowledge base is a single hashable file whose sha256 and size can be pinned in the SecurityKnowledgeBaseRef.","triggerScenarios":"Calling knowledgeBases()/normalizeKnowledgeBases with a `paths` entry that resolves to a directory (e.g. passing a folder like ./kb or ./kb/ instead of ./kb/rules.md), or to a non-regular file (FIFO, device, socket).","commonSituations":"Config points at a knowledge-base directory instead of the file inside it; trailing-slash path that auto-completes to a directory; a docs folder that used to contain a single file; symlink to a directory used as a shortcut.","solutions":["Point the knowledge base entry at the specific file (e.g. ./kb/rules.md), not its parent directory.","Run `ls -l` on the path to confirm it is a regular file, not a directory or special file.","If you intended multiple files, list each file as a separate entry in paths."],"exampleFix":"// before\n{ \"knowledgeBases\": [\"./security/kb\"] }\n// after\n{ \"knowledgeBases\": [\"./security/kb/rules.md\", \"./security/kb/policy.md\"] }","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nfor (const kb of paths) {\n  const resolved = path.resolve(baseDirectory, kb);\n  const st = await fs.stat(resolved);\n  if (!st.isFile()) throw new Error(`Knowledge base must be a regular file: ${kb}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await knowledgeBases(baseDirectory, paths);\n} catch (err) {\n  if ((err as Error).message.includes(\"is not a file\")) {\n    // surface which path was wrong and stop configuration load\n  }\n  throw err;\n}","preventionTips":["Always list individual files, never directories, in knowledge base config.","Run `file <path>` or `ls -l` on each configured path before starting a scan.","Keep knowledge base files in a dedicated directory so glob/directory mistakes are obvious."],"tags":["filesystem","validation","security","path"],"backgroundTag":"expected-file-found-directory","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}