tobi/qmd · info
OUTSIDE_COLLECTION
OUTSIDE_COLLECTION
Error message
OUTSIDE_COLLECTION
What it means
During collection indexing (qmd collection add / update), a candidate file resolved to a real path outside the collection root directory (isPathInsideDir failed). The file is skipped and recorded with code OUTSIDE_COLLECTION — symlinks escaping the collection are the usual cause (getRealPath resolves them).
Source
Thrown at src/cli/qmd.ts:1962
console.log("No files found matching pattern.");
// Continue so the deactivation pass can mark previously indexed docs as inactive.
}
let indexed = 0, updated = 0, unchanged = 0, processed = 0;
const skippedFiles: { file: string; code: string }[] = [];
const seenPaths = new Set<string>();
// Literal paths of every file in this scan. Passed to the legacy-path
// migration so it never adopts a row that still belongs to a live file.
const livePaths = new Set(files.map(f => f.replace(/\\/g, '/')));
const startTime = Date.now();
for (const relativeFile of files) {
const filepath = getRealPath(resolve(resolvedPwd, relativeFile));
// Store the literal relative path — handelize() is NOT applied at index time.
const path = relativeFile.replace(/\\/g, '/');
if (!isPathInsideDir(resolvedPwd, filepath)) {
processed++;
skippedFiles.push({ file: relativeFile, code: "OUTSIDE_COLLECTION" });
progress.set((processed / total) * 100);
continue;
}
seenPaths.add(path);
let content: string;
try {
content = readFileSync(filepath, "utf-8");
} catch (err) {
// Skip files that can't be read (ETIMEDOUT, EAGAIN, EACCES, …) (#460)
processed++;
skippedFiles.push({ file: relativeFile, code: fsErrorCode(err) });
progress.set((processed / total) * 100);
continue;
}
// Skip empty files - nothing useful to index
if (!content.trim()) {View on GitHub (pinned to dbfd0b4736)
Solutions
- If the target should be indexed, add its real location as its own collection instead of a symlink
- Replace the symlink with the actual directory or copy files inside the root
- Ignore the skip — it is informational; the rest of the collection still indexes
Example fix
# before ~/notes/repo -> /home/me/src/repo (symlink escapes collection) # after qmd collection add /home/me/src/repo --name repo # index real path directly
Defensive patterns
Strategy: fallback
Validate before calling
const real = fs.realpathSync(file); if (isPathInsideDir(collectionRoot, real)) indexFile(file); else skip();
Type guard
const isInsideCollection = (root: string, f: string) => isPathInsideDir(root, fs.realpathSync(f));
Prevention
- Avoid symlinks pointing outside collection roots
- Add real locations as their own collections
- Treat OUTSIDE_COLLECTION skips as informational, not fatal
When it happens
Trigger: Indexing a directory containing a symlink whose target lives outside the collection root; files listed by the scanner whose realpath resolves elsewhere (e.g. symlinks into ~/.config or another collection's dir).
Common situations: Symlinked dotfile dirs (e.g. vim/nvim config symlinking to a repo), monorepo workspaces symlinked from a parent folder, or masked paths pointing at absolute targets.
Related errors
- OUTSIDE_COLLECTION
- ⚠ Skipped file outside collection: ${skipped.file}
- Collection '${collection}' has no indexed documents.\nRun 'q
- Collection not found: ${collection}\n${hint}
- No indexed documents found.\nIndex a collection with 'qmd co
AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28).
Data as JSON: /api/errors/7f40dfc1f0c602e0.
Report an issue: GitHub.