{"record":{"id":"16a4131762622e46","repo":"JuliusBrussee/caveman","slug":"initialtoolcount-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"initialToolCount must be a non-negative integer","messagePattern":"initialToolCount must be a non-negative integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sdk/typescript/src/index.ts","lineNumber":475,"sourceCode":"\n  /**\n   * Build a tool-catalog handle with server-side search via /sdk/v1/tool-search.\n   *\n   * strategy \"all\"      → initial = whole catalog; search() still calls the server.\n   * strategy \"deferred\" → initial = alwaysLoad tools (subset sent on first turn);\n   *                       search() calls the server to load relevant tools on demand.\n   *\n   * Breaking change from 1.0: search() is now async and returns ToolSearchResult\n   * (previously sync, returning CaveTool[]). Callers must await search().\n   */\n  tools(config: { catalog: CaveTool[]; strategy?: \"all\" | \"deferred\"; initialToolCount?: number; maxLoadedTools?: number }) {\n    const strategy = config.strategy ?? \"all\";\n    if (strategy !== \"all\" && strategy !== \"deferred\") {\n      throw new Error(\"strategy must be all or deferred\");\n    }\n    const initialToolCount = config.initialToolCount ?? 8;\n    if (!Number.isSafeInteger(initialToolCount) || initialToolCount < 0) {\n      throw new Error(\"initialToolCount must be a non-negative integer\");\n    }\n    if (config.maxLoadedTools !== undefined && (!Number.isSafeInteger(config.maxLoadedTools) || config.maxLoadedTools < 1)) {\n      throw new Error(\"maxLoadedTools must be a positive integer\");\n    }\n    let initial: CaveTool[];\n    if (strategy === \"all\") {\n      initial = config.catalog.slice();\n    } else {\n      const always = config.catalog.filter((tool) => tool.alwaysLoad);\n      if (config.maxLoadedTools !== undefined && always.length > config.maxLoadedTools) {\n        throw new Error(\"maxLoadedTools must be at least the alwaysLoad tool count\");\n      }\n      const lazy = config.catalog.filter((tool) => !tool.alwaysLoad);\n      const lazyLimit = config.maxLoadedTools === undefined\n        ? initialToolCount\n        : Math.min(initialToolCount, config.maxLoadedTools - always.length);\n      initial = always.concat(lazy.slice(0, lazyLimit));\n    }","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/sdk/typescript/src/index.ts#L457-L493","documentation":"The tools() descriptor validates initialToolCount (default 8): when provided it must be a safe integer >= 0. Negative numbers, non-integers, NaN/Infinity, or out-of-range values are rejected. This count decides how many tools are pre-loaded in the deferred strategy, so it must be a valid array-size-like number.","triggerScenarios":"cave.tools({ catalog, initialToolCount: -1 }) (e.g. \"auto\" intent), initialToolCount: 2.5, initialToolCount: Number(config.initialToolCount) yielding NaN, or initialToolCount exceeding catalog length with an unsafe/huge value.","commonSituations":"Config parsing leaving the value as a string or producing NaN; computing the count from catalog.length - n going negative for tiny catalogs; seconds/millis or percentage confusion producing fractional values.","solutions":["Pass a non-negative integer (e.g. initialToolCount: 4) or omit the option to use the default of 8.","Clamp computed values: `initialToolCount: Math.max(0, Math.trunc(count))`.","Coerce config values with Number() and validate Number.isSafeInteger(v) && v >= 0 before calling."],"exampleFix":"// before\ncave.tools({ catalog, initialToolCount: catalog.length - 10 }); // negative for small catalogs\n\n// after\ncave.tools({ catalog, initialToolCount: Math.max(0, catalog.length - 10) });","handlingStrategy":"validation","validationCode":"function parseInitialToolCount(raw: unknown): number | undefined {\n  if (raw === undefined) return undefined;\n  const n = Number(raw);\n  if (!Number.isSafeInteger(n) || n < 0) throw new Error(`initialToolCount must be a non-negative integer, got ${String(raw)}`);\n  return n;\n}","typeGuard":"const isValidInitialToolCount = (v: unknown): v is number =>\n  typeof v === \"number\" && Number.isSafeInteger(v) && v >= 0;","tryCatchPattern":"try {\n  const desc = cave.tools({ catalog, initialToolCount });\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"initialToolCount\")) {\n    const desc = cave.tools({ catalog }); // default of 8\n  } else throw e;\n}","preventionTips":["Clamp computed counts with Math.max(0, Math.trunc(v)) before passing.","Omit initialToolCount to use the default (8).","Validate config-sourced numbers with Number.isSafeInteger before use."],"tags":["validation","argument-out-of-range","tools","configuration"],"backgroundTag":"value-out-of-range","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}