tobi/qmd · error · Error
${name} must be a positive integer
Error message
${name} must be a positive integer What it means
resolveEmbedOptions() validates numeric embedding options (maxDocsPerBatch, maxBatchBytes) via validatePositiveIntegerOption, which rejects any value that is not an integer >= 1. Undefined falls back to the default, but 0, negatives, floats, NaN, or strings that coerce incorrectly throw.
Source
Thrown at src/store.ts:1800
body: string;
};
type ChunkItem = {
hash: string;
path: string;
title: string;
text: string;
seq: number;
pos: number;
tokens: number;
bytes: number;
expectedTotalChunks: number;
};
function validatePositiveIntegerOption(name: string, value: number | undefined, fallback: number): number {
if (value === undefined) return fallback;
if (!Number.isInteger(value) || value < 1) {
throw new Error(`${name} must be a positive integer`);
}
return value;
}
function resolveEmbedOptions(options?: EmbedOptions): Required<Pick<EmbedOptions, "maxDocsPerBatch" | "maxBatchBytes">> {
return {
maxDocsPerBatch: validatePositiveIntegerOption("maxDocsPerBatch", options?.maxDocsPerBatch, DEFAULT_EMBED_MAX_DOCS_PER_BATCH),
maxBatchBytes: validatePositiveIntegerOption("maxBatchBytes", options?.maxBatchBytes, DEFAULT_EMBED_MAX_BATCH_BYTES),
};
}
const CONTENT_VECTOR_DESIRED_COLUMNS: { name: string; definition: string }[] = [
{ name: "seq", definition: "INTEGER NOT NULL DEFAULT 0" },
{ name: "pos", definition: "INTEGER NOT NULL DEFAULT 0" },
{ name: "model", definition: "TEXT NOT NULL DEFAULT ''" },
{ name: "embed_fingerprint", definition: "TEXT NOT NULL DEFAULT ''" },
{ name: "total_chunks", definition: "INTEGER NOT NULL DEFAULT 1" },
{ name: "embedded_at", definition: "TEXT NOT NULL DEFAULT ''" },View on GitHub (pinned to dbfd0b4736)
Solutions
- Pass a positive integer >= 1 or omit the option to use the default
- Fix the computation producing 0/float/NaN before calling embed
- Clamp: Math.max(1, Math.floor(value))
Example fix
// before
embed(docs, { maxDocsPerBatch: 0 });
// after
embed(docs, { maxDocsPerBatch: Math.max(1, Math.floor(opts.batch || DEFAULT)) }); Defensive patterns
Strategy: validation
Validate before calling
const safe = (v?: number, fb: number) => v == null ? fb : (Number.isInteger(v) && v >= 1 ? v : undefined!); // validate before pass
Type guard
const isValidBatchOpt = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 1;
Prevention
- Clamp computed options: Math.max(1, Math.floor(x))
- Reject 0/NaN early at config parse time
- Omit options to use defaults when unsure
When it happens
Trigger: Passing embed options like { maxDocsPerBatch: 0 } or { maxBatchBytes: 1.5 } to the embedding pipeline that calls resolveEmbedOptions.
Common situations: Config/env overrides parsed as 0 by mistake; computing a batch size dynamically and getting 0 on empty input; passing a float from a ratio calculation.
Understand the failure class
Background: Invalid option value errors: "must be one of", "is not a valid", and "only allows" failures explained — this error's family across 23 libraries.
Related errors
- Line ${line.number} is missing a lex:/vec:/hyde:/intent: pre
- intent: cannot appear alone. Add at least one lex:, vec:, or
- dbPath is required
- Provide either configPath or config, not both
- search() requires either 'query' or 'queries'
AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28).
Data as JSON: /api/errors/e5dd5ec18e9c2db7.
Report an issue: GitHub.