affaan-m/ECC · error · Error
Invalid warn threshold: ${options.warnThreshold}
Error message
Invalid warn threshold: ${options.warnThreshold} What it means
Thrown by collectSkillHealth when options.warnThreshold, after Number() coercion (default 0.1), is not finite or is negative. warnThreshold is the fraction below which a skill's success-rate decline raises a warning.
Source
Thrown at scripts/lib/skill-evolution/health.js:156
timeMs: Date.parse(record.recorded_at),
}))
.filter(entry => !Number.isNaN(entry.timeMs))
.sort((left, right) => left.timeMs - right.timeMs)
.at(-1)?.timestamp || null;
}
function collectSkillHealth(options = {}) {
const now = options.now || new Date().toISOString();
const nowMs = Date.parse(now);
if (Number.isNaN(nowMs)) {
throw new Error(`Invalid now timestamp: ${now}`);
}
const warnThreshold = typeof options.warnThreshold === 'number'
? options.warnThreshold
: Number(options.warnThreshold || 0.1);
if (!Number.isFinite(warnThreshold) || warnThreshold < 0) {
throw new Error(`Invalid warn threshold: ${options.warnThreshold}`);
}
const records = tracker.readSkillExecutionRecords(options);
const skillsById = discoverSkills(options);
const recordsBySkill = records.reduce((groupedRecords, record) => {
if (!groupedRecords.has(record.skill_id)) {
groupedRecords.set(record.skill_id, []);
}
groupedRecords.get(record.skill_id).push(record);
return groupedRecords;
}, new Map());
for (const skillId of recordsBySkill.keys()) {
if (!skillsById.has(skillId)) {
skillsById.set(skillId, {
skill_id: skillId,
skill_dir: null,View on GitHub (pinned to 01e15490f0)
Solutions
- Pass a non-negative finite number (fraction in 0..1, e.g. 0.1 for 10%).
- Omit options.warnThreshold to use the built-in default of 0.1.
- If reading from config/env, coerce and bounds-check before calling.
Example fix
// before
collectSkillHealth({ warnThreshold: process.env.WARN_THRESHOLD });
// env unset -> '' -> Number('') === 0, ok; but 'high' -> NaN -> throws
// after
const wt = Number(process.env.WARN_THRESHOLD || 0.1);
collectSkillHealth({ warnThreshold: Number.isFinite(wt) && wt >= 0 ? wt : 0.1 }); Defensive patterns
Strategy: validation
Validate before calling
function resolveWarnThreshold(raw) {
const n = typeof raw === 'number' ? raw : Number(raw);
if (!Number.isFinite(n) || n < 0) return 0.1; // safe default
return n;
}
health.collectSkillHealth({ ...opts, warnThreshold: resolveWarnThreshold(opts.warnThreshold) }); Type guard
function isValidWarnThreshold(v) {
const n = Number(v);
return Number.isFinite(n) && n >= 0;
} Try / catch
try {
collectSkillHealth({ warnThreshold });
} catch (err) {
if (/Invalid warn threshold/.test(err.message)) collectSkillHealth({ ...opts });
else throw err;
} Prevention
- Express warnThreshold as a fraction (0..1), not a percentage.
- Coerce env/config values with Number() and bounds-check before passing.
- Default to omitting the option (0.1) when unsure.
When it happens
Trigger: Calling collectSkillHealth({ warnThreshold: 'abc' }) (Number('abc') = NaN), { warnThreshold: -0.2 }, or { warnThreshold: Infinity }. A numeric string like '0.1' is accepted because Number('0.1') = 0.1.
Common situations: Config typo passing a non-numeric; passing a negative value by mistake; confusing the threshold as a percentage (passing 10 for '10%') — that won't throw but yields wrong warnings; env var defaulting to an empty/non-numeric string.
Related errors
- Invalid now timestamp: ${now}
- ECC_PROJECT_DIR must be a child path within /workspace.
- Unknown argument: ${arg}
- Unable to infer ECC repo root from install-state operations
- Invalid ECC repo root: missing package.json at ${packageJson
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/239c07da63f8414f.
Report an issue: GitHub.