JuliusBrussee/caveman · error

caveman agent: context ttlTurns must be a positive integer

Error message

caveman agent: context ttlTurns must be a positive integer

What it means

context() validates that ttlTurns, when provided, is a positive safe integer (Number.isSafeInteger and > 0). The library throws this error at definition time to reject context definitions with an invalid time-to-live, such as zero, negative, fractional, or non-integer values. It is a synchronous constructor-style validation so misuse fails immediately rather than silently misbehaving at runtime.

Solutions

  1. Pass a positive integer for ttlTurns (>= 1), or omit the property entirely if the context should not expire.
  2. Validate/round the value before calling context(): Number.isSafeInteger(v) && v > 0.
  3. If ttlTurns comes from config, coerce and check it: Math.floor(Number(raw)) and reject non-finite values.

Example fix

// before
const ctx = context({ id: "history", ttlTurns: 0 });
// after
const ctx = context({ id: "history", ttlTurns: 10 }); // or omit ttlTurns
Defensive patterns

Strategy: validation

Validate before calling

function validTtlTurns(v) { return v === undefined || (Number.isSafeInteger(v) && v > 0); }
if (!validTtlTurns(opts.ttlTurns)) throw new Error(`ttlTurns must be a positive integer, got ${opts.ttlTurns}`);

Type guard

function isPositiveInt(v: unknown): v is number { return typeof v === "number" && Number.isSafeInteger(v) && v > 0; }

Try / catch

let ctx;
try { ctx = context({ id: "history", ttlTurns }); }
catch (e) { if (String(e.message).includes("ttlTurns")) ctx = context({ id: "history" }); else throw e; }

Prevention

When it happens

Trigger: Calling context({ id, ttlTurns }) where ttlTurns is 0, negative (e.g. -1), a float (e.g. 2.5), NaN, Infinity, or otherwise not a Number.isSafeInteger. Any other option value does not trigger this error.

Common situations: Computing ttlTurns from config math that yields a float or negative number; passing a string parsed value without coercion; using a default placeholder of 0 intending 'no expiry' instead of omitting ttlTurns.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/8301edad241dfd05. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/primitives.ts:350

  readonly ttlTurns?: number;
}

export function context(options: {
  id: string;
  kind: ContextKind;
  source: string | FileSource;
  stability: ContextStability;
  safety?: SafetyClass;
  priority?: ContextPriority;
  recovery?: RecoveryKind;
  cacheRegion?: CacheRegion;
  privacy?: PrivacyClass;
  opaque?: boolean;
  ttlTurns?: number;
}): ContextDefinition {
  if (options.id.trim() === "") throw new Error("caveman agent: context id is required");
  if (options.ttlTurns !== undefined && (!Number.isSafeInteger(options.ttlTurns) || options.ttlTurns <= 0)) {
    throw new Error("caveman agent: context ttlTurns must be a positive integer");
  }
  const definition: ContextDefinition = {
    kind: "context",
    id: options.id,
    segmentKind: options.kind,
    source: options.source,
    stability: options.stability,
    safety: options.safety ?? "S0",
    priority: options.priority ?? "required",
    recovery: options.recovery ?? "none",
    cacheRegion: options.cacheRegion ?? (options.stability === "build" ? "frozen_prefix" : "live_zone"),
    privacy: options.privacy ?? "local_sensitive",
    opaque: options.opaque ?? false,
    ...(options.ttlTurns === undefined ? {} : { ttlTurns: options.ttlTurns }),
  };
  return Object.freeze(definition);
}

View on GitHub (pinned to 3ee70a1026)