Hmbown/CodeWhale · error · Error
--attempts must be an integer from 1 to 20
Error message
--attempts must be an integer from 1 to 20
What it means
Thrown by the post-deploy drift gate web/scripts/compare-deployed-facts.mjs when an explicitly passed --attempts value is not an integer in [1, 20]. The value goes through Number(argv[++index]), so a non-numeric token becomes NaN, decimals like 3.5 fail Number.isInteger, and 0 or 21 fail the range check. When the flag is omitted the script defaults to 6 attempts with --require-current and 1 otherwise, so only an explicitly bad value reaches this throw.
Source
Thrown at web/scripts/compare-deployed-facts.mjs:116
async function main() {
const args = parseArgs(process.argv.slice(2));
let baseUrl;
try {
baseUrl = new URL(args.baseUrl);
} catch {
throw new Error(`invalid --base-url: ${args.baseUrl}`);
}
if (!/^https?:$/.test(baseUrl.protocol)) {
throw new Error("--base-url must use http or https");
}
const expectedRevision = args.expectedRevision || localRevision();
if (!expectedRevision || !/^[0-9a-f]{40}$/i.test(expectedRevision)) {
throw new Error("expected revision must be an exact 40-character Git SHA");
}
if (!Number.isInteger(args.attempts) || args.attempts < 1 || args.attempts > 20) {
throw new Error("--attempts must be an integer from 1 to 20");
}
if (!Number.isFinite(args.retryDelayMs) || args.retryDelayMs < 0 || args.retryDelayMs > 30_000) {
throw new Error("--retry-delay-ms must be between 0 and 30000");
}
const facts = buildFacts();
const expected = {
sourceRevision: expectedRevision,
version: facts.version,
providerCount: facts.providers.length,
toolCount: facts.toolCount,
latestPublishedRelease: facts.latestPublishedRelease,
};
const endpoint = new URL("/api/facts", baseUrl).toString();
let last = { error: "not attempted" };
let differences = [];
for (let attempt = 1; attempt <= args.attempts; attempt += 1) {View on GitHub (pinned to 8880682c63)
Solutions
- Pass an integer from 1 to 20, for example --attempts 6
- Omit the flag entirely; the default is already 6 with --require-current and 1 without
- Coerce and clamp sourced values before invoking: Math.min(20, Math.max(1, parseInt(value, 10)))
- Check wrapper scripts for a --attempts token whose value was dropped by quoting
Example fix
// before node web/scripts/compare-deployed-facts.mjs --require-current --attempts 3.5 // after node web/scripts/compare-deployed-facts.mjs --require-current --attempts 4
Defensive patterns
Strategy: validation
Validate before calling
// validate before spawning the gate script
const raw = Number(process.env.DEPLOY_ATTEMPTS ?? '');
const valid = Number.isInteger(raw) && raw >= 1 && raw <= 20;
const args = ['web/scripts/compare-deployed-facts.mjs'];
if (valid) args.push('--attempts', String(raw)); // otherwise let the script default apply Prevention
- Type retry counts as integers where they originate (CI variables, config schemas)
- Prefer omitting optional numeric flags over forwarding computed values
- Echo accepted ranges in wrapper usage text beside where flags are assembled
When it happens
Trigger: Running the script with --attempts 0, --attempts 21, --attempts 3.5, --attempts abc (NaN), or a trailing --attempts whose value token is missing so Number(undefined) yields NaN.
Common situations: CI pipelines injecting retry counts from matrix variables or env vars that arrive as floats or empty strings; copying a --tries-style flag from another tool; wrapper scripts quoting away the value token.
Related errors
- --retry-delay-ms must be between 0 and 30000
- Usage: node scripts/release/assemble-release-assets.js INP
- Invalid GitHub repository: ${repo}
- Invalid release tag: ${tag}
- unknown argument: ${arg}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/5ffc3ade2016f9eb.
Report an issue: GitHub.