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

  1. Pass a positive integer >= 1 or omit the option to use the default
  2. Fix the computation producing 0/float/NaN before calling embed
  3. 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

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


AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28). Data as JSON: /api/errors/e5dd5ec18e9c2db7. Report an issue: GitHub.