tobi/qmd · warning
⚠ Skipped file outside collection: ${skipped.file}
Error message
⚠ Skipped file outside collection: ${skipped.file} What it means
reportSkippedReads in the CLI prints '⚠ Skipped file outside collection: {file}' for every entry in skippedFiles whose code is OUTSIDE_COLLECTION — i.e. it is the user-facing echo of the store-level skip from src/store.ts (error 60). It means the indexer refused to ingest those files because their resolved path (via glob `../`, absolute patterns, or symlinks) lies outside the collection root, and any previously indexed copies are deactivated.
Source
Thrown at src/cli/qmd.ts:2069
console.log(`\nRun 'qmd embed' to update embeddings (${needsEmbedding} unique hashes need vectors)`);
}
closeDb();
}
function fsErrorCode(err: unknown): string {
if (err && typeof err === "object" && "code" in err) {
const code = (err as { code: unknown }).code;
if (typeof code === "string" && code.length > 0) return code;
}
return "ERROR";
}
function reportSkippedReads(skippedFiles: { file: string; code: string }[]): void {
if (skippedFiles.length === 0) return;
for (const skipped of skippedFiles) {
if (skipped.code === "OUTSIDE_COLLECTION") {
console.warn(`⚠ Skipped file outside collection: ${skipped.file}`);
} else {
console.warn(`⚠ Skipped unreadable file: ${skipped.file} (${skipped.code})`);
}
}
const escaped = skippedFiles.filter(f => f.code === "OUTSIDE_COLLECTION").length;
const unreadable = skippedFiles.length - escaped;
if (escaped) console.warn(`Skipped ${escaped} file(s) outside the collection root`);
if (unreadable) console.warn(`Skipped ${unreadable} unreadable file(s)`);
}
function renderProgressBar(percent: number, width: number = 30): string {
const filled = Math.round((percent / 100) * width);
const empty = width - filled;
const bar = "█".repeat(filled) + "░".repeat(empty);
return bar;
}
function parseEmbedBatchOption(name: string, value: unknown): number | undefined {View on GitHub (pinned to dbfd0b4736)
Solutions
- Fix the `--mask` so it cannot escape the collection root (no `../` segments, no absolute patterns) and re-run `qmd update`
- Add the outside directory as its own collection: `qmd collection add <dir> --name <n>`
- Resolve escaping symlinks: replace them with real files under the root, or move their targets inside the collection
- If the layout is intentional, re-add the collection with a higher-level root so all desired files are inside it
Example fix
# before qmd collection add ~/notes --name notes --mask '**/*.md,../*.md' # update prints: ⚠ Skipped file outside collection: ../todo.md # after qmd collection remove notes qmd collection add ~/notes --name notes --mask '**/*.md' qmd collection add ~ --name home-notes --mask 'todo.md'
Defensive patterns
Strategy: validation
Validate before calling
// Before qmd update: verify every matched file resolves inside the collection root
import { globSync } from 'glob';
import path from 'node:path';
function findEscapes(root: string, mask: string): string[] {
const absRoot = path.resolve(root);
return globSync(mask, { cwd: absRoot, follow: true, dot: true })
.map(f => path.resolve(absRoot, f))
.filter(f => !f.startsWith(absRoot + path.sep));
}
const escapes = findEscapes('/home/me/notes', '**/*.md');
if (escapes.length) console.warn('Will be skipped as OUTSIDE_COLLECTION:', escapes); Type guard
function maskStaysInsideRoot(mask: string): boolean {
return mask.split(',').every(part => {
const p = part.trim().replace(/^!/, '');
return !path.isAbsolute(p) && !p.split(/[\\/]/).includes('..');
});
} Prevention
- Keep masks root-relative and simple ('**/*.md')
- Review the skipped-file warnings after every qmd update; each line names the escaping file
- Check for repointed symlinks after moving directories: find . -type l -exec readlink -f {} \;
- Add external directories as separate collections rather than escaping with globs
When it happens
Trigger: After any indexing run (`qmd collection add`, `qmd update`), the CLI reports each file the store skipped with code OUTSIDE_COLLECTION. The underlying conditions are the same as error 60: escaping glob masks, absolute mask patterns, or file symlinks resolving outside the collection root.
Common situations: Right after adding a collection whose mask accidentally matches files above the root; on `qmd update` after symlinks in the collection were repointed to external targets; after moving the collection directory so old indexed paths now resolve outside; dotfiles-style symlinked note folders.
Related errors
- OUTSIDE_COLLECTION
- OUTSIDE_COLLECTION
- 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/8358d2027f9dd8a5.
Report an issue: GitHub.