can1357/oh-my-pi · error · Error

Security knowledge base is not a file: ${input}

Error message

Security knowledge base is not a file: ${input}

What it means

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.

Source

Thrown at packages/coding-agent/src/security/preflight.ts:235

		repositoryRoot,
		displayName,
		includePaths,
		excludePaths,
		treeDigest: await digestWorkingTree(repositoryRoot, includePaths, excludePaths, adapter, signal),
	};
	if (revision !== null) target.revision = revision;
	return target;
}

async function normalizeKnowledgeBases(
	paths: readonly string[] | undefined,
	baseDirectory: string,
): Promise<SecurityKnowledgeBaseRef[]> {
	const results: SecurityKnowledgeBaseRef[] = [];
	for (const input of paths ?? []) {
		const canonical = await fs.realpath(path.resolve(baseDirectory, input));
		const stats = await fs.stat(canonical);
		if (!stats.isFile()) throw new Error(`Security knowledge base is not a file: ${input}`);
		const digest = await hashFile(canonical);
		results.push({ path: canonical, sha256: digest.sha256, size: digest.size });
	}
	return results.sort((left, right) => left.path.localeCompare(right.path));
}

async function normalizeOutput(
	repositoryRoot: string,
	outputRoot: string,
	archiveExisting: boolean,
): Promise<SecurityOutputPlan> {
	const requested = path.resolve(outputRoot);
	const parent = await fs.realpath(path.dirname(requested));
	const canonicalCandidate = path.join(parent, path.basename(requested));
	if (pathIsWithin(canonicalCandidate, repositoryRoot)) {
		throw new Error("Security output directory must be outside the scanned repository");
	}
	let existingState: SecurityOutputPlan["existingState"] = "absent";

View on GitHub (pinned to 9690622007)

Solutions

  1. Point the knowledge base entry at the specific file (e.g. ./kb/rules.md), not its parent directory.
  2. Run `ls -l` on the path to confirm it is a regular file, not a directory or special file.
  3. If you intended multiple files, list each file as a separate entry in paths.

Example fix

// before
{ "knowledgeBases": ["./security/kb"] }
// after
{ "knowledgeBases": ["./security/kb/rules.md", "./security/kb/policy.md"] }
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs/promises";
import * as path from "node:path";
for (const kb of paths) {
  const resolved = path.resolve(baseDirectory, kb);
  const st = await fs.stat(resolved);
  if (!st.isFile()) throw new Error(`Knowledge base must be a regular file: ${kb}`);
}

Try / catch

try {
  await knowledgeBases(baseDirectory, paths);
} catch (err) {
  if ((err as Error).message.includes("is not a file")) {
    // surface which path was wrong and stop configuration load
  }
  throw err;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/149a7bc8b0e1f0e7. Report an issue: GitHub.