affaan-m/ECC · error · Error
Invalid warn threshold
Error message
Invalid warn threshold: ${options.warnThreshold} What it means
collectSkillHealth validates options.warnThreshold, the fraction (0..1 scale) of stale executions at which a skill is flagged as unhealthy. The value must be a finite number >= 0; strings that Number() cannot convert to a finite non-negative value, NaN, Infinity, and negatives all throw this error.
Solutions
- Pass a finite non-negative number, e.g. collectSkillHealth({ warnThreshold: 0.1 }).
- Parse percentages at the boundary: Number(value.replace('%','')) / 100 before calling.
- Guard in the caller: const t = Number(raw); if (!Number.isFinite(t) || t < 0) reject before invoking.
- Omit warnThreshold to use the default 0.1.
Example fix
// before
health.collectSkillHealth({ warnThreshold: '10%' });
// after
const raw = '10%';
health.collectSkillHealth({ warnThreshold: Number(raw.replace('%', '')) / 100 }); // 0.1 Defensive patterns
Strategy: validation
Validate before calling
function toWarnThreshold(raw) {
const n = typeof raw === 'string' && raw.endsWith('%') ? Number(raw.slice(0, -1)) / 100 : Number(raw);
if (!Number.isFinite(n) || n < 0) throw new Error(`warnThreshold must be a finite number >= 0, got: ${raw}`);
return n;
} Type guard
const isValidThreshold = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
Try / catch
try {
report = health.collectSkillHealth({ warnThreshold: raw });
} catch (err) {
if (err.message.startsWith('Invalid warn threshold')) {
console.error(`Bad --warn-threshold '${raw}'; using default 0.1.`);
report = health.collectSkillHealth({});
} else throw err;
} Prevention
- Parse numeric CLI flags with Number() and reject NaN at the argument boundary.
- Store thresholds as fractions (0.1), never percent strings ('10%').
- Document the expected range in config schema/comments.
When it happens
Trigger: collectSkillHealth({ warnThreshold: 'high' }); passing warnThreshold: -0.5; passing NaN or Infinity; passing an object/boolean that Number() coerces to NaN (e.g. {} or undefined-like strings where Number('' || 0.1) traps differ from intent).
Common situations: CLI --warn-threshold flags passed as raw unparsed strings ('--warn-threshold 0.2' forwarded as ' 0.2 ' with whitespace is fine, but 'twenty percent' is not); config files with percentage strings like '10%' instead of 0.1; copy-pasted negative or typo'd values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Choose at least one guided harness: Claude, Codex, or Kimi.
- failure.reason
- genre has no references
- Invalid : unsupported hook event
- Invalid now timestamp
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/239c07da63f8414f.
Report an issue: GitHub.
Appendix: 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 8321021c54)