{"record":{"id":"0233a30a576704b0","repo":"JuliusBrussee/caveman","slug":"cave-setup-timeout-must-be-a-positive-integer-got-0233a3","errorCode":null,"errorMessage":"CAVE_SETUP_TIMEOUT must be a positive integer (got ${JSON.stringify(raw)})","messagePattern":"CAVE_SETUP_TIMEOUT must be a positive integer \\(got (.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/binary-installer/installer.mjs","lineNumber":82,"sourceCode":"\nexport function targetPlatform(os = process.platform, nodeArch = process.arch) {\n  const arch = nodeArch === \"x64\" ? \"amd64\" : nodeArch;\n  if (!(os === \"darwin\" || os === \"linux\" || os === \"win32\") ||\n      !(arch === \"arm64\" || arch === \"amd64\")) {\n    throw new Error(`no prebuilt binary for ${os}/${arch} — supported: darwin/arm64, darwin/amd64, linux/arm64, linux/amd64, win32/arm64, win32/amd64`);\n  }\n  return { os, arch };\n}\n\nexport function binaryInstallFilename(name, os = process.platform) {\n  return os === \"win32\" ? `${name}.exe` : name;\n}\n\nfunction timeoutMs() {\n  const raw = process.env.CAVE_SETUP_TIMEOUT ?? \"300\";\n  const seconds = Number(raw);\n  if (!Number.isInteger(seconds) || seconds <= 0) {\n    throw new Error(`CAVE_SETUP_TIMEOUT must be a positive integer (got ${JSON.stringify(raw)})`);\n  }\n  return seconds * 1000;\n}\n\nasync function asset(url, timeout) {\n  let response;\n  try {\n    response = await fetch(url, { signal: AbortSignal.timeout(timeout) });\n  } catch (error) {\n    throw new Error(`binary download failed: ${error.message}`);\n  }\n  if (!response.ok) throw new Error(`binary download failed: HTTP ${response.status}`);\n  return response;\n}\n\nfunction signedDigest(checksums, bundleRaw) {\n  try {\n    const bundle = JSON.parse(bundleRaw);","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/shared/binary-installer/installer.mjs#L64-L100","documentation":"The installer reads the optional CAVE_SETUP_TIMEOUT env var (seconds) and converts it to milliseconds. `timeoutMs` throws when the variable is set but not parseable as a positive integer, since a bogus value would silently break download timeouts.","triggerScenarios":"CAVE_SETUP_TIMEOUT set to a non-integer (\"12.5\", \"abc\", \"\"), zero, a negative number, or a value with spaces/units (\"300s\").","commonSituations":"Typo in CI config adding a unit suffix; empty string from an unset-but-exported variable; decimal entered by someone expecting sub-second precision; locale-formatted number.","solutions":["Set CAVE_SETUP_TIMEOUT to a plain positive integer, e.g. 300","Remove the variable entirely to use the default of 300 seconds","Fix the CI/env file so no stray characters (units, spaces, quotes) leak into the value","If you need sub-second precision, the variable doesn't support it — keep whole seconds"],"exampleFix":"// before\nCAVE_SETUP_TIMEOUT=90s\n// after\nCAVE_SETUP_TIMEOUT=90","handlingStrategy":"validation","validationCode":"const raw = process.env.CAVE_SETUP_TIMEOUT;\nif (raw !== undefined && (!/^[1-9]\\d*$/.test(raw.trim()))) {\n  throw new Error(`CAVE_SETUP_TIMEOUT must be a positive integer, got ${JSON.stringify(raw)}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await setup();\n} catch (e) {\n  if (String(e.message).startsWith(\"CAVE_SETUP_TIMEOUT must be a positive integer\")) {\n    console.error(\"Fix CAVE_SETUP_TIMEOUT (plain integer seconds) or unset it for the 300s default\");\n  } else throw e;\n}","preventionTips":["Set whole seconds with no units: CAVE_SETUP_TIMEOUT=600","Never export the variable empty; unset it to use the default","Validate env vars in CI before running setup steps","Document that sub-second timeouts are not supported"],"tags":["env","config","timeout"],"backgroundTag":"invalid-env-var-value","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"}