affaan-m/ECC · error · Error
Invalid now timestamp
Error message
Invalid now timestamp: ${now} What it means
renderDashboard accepts an options.now timestamp that overrides the current time used for staleness/health calculations. The value is parsed with Date.parse and must be a valid date string; anything unparseable produces NaN, which would silently corrupt all age computations, so the dashboard throws instead.
Solutions
- Pass a valid ISO 8601 string, e.g. renderDashboard({ now: new Date().toISOString() }).
- Coerce before calling: const nowMs = Date.parse(opts.now); if (Number.isNaN(nowMs)) fix/throw in the caller.
- If the value comes from a CLI flag, validate/parse it at the CLI boundary and report a friendly usage error.
- Omit `now` entirely to let the dashboard default to the current time.
Example fix
// before
renderDashboard({ now: process.env.REPORT_DATE }); // 'March 15th'
// after
const raw = process.env.REPORT_DATE;
renderDashboard(raw ? { now: new Date(raw).toISOString() } : {}); Defensive patterns
Strategy: validation
Validate before calling
const nowMs = Date.parse(opts.now ?? new Date().toISOString());
if (Number.isNaN(nowMs)) throw new Error(`--now must be an ISO date, got: ${opts.now}`); Type guard
const isIsoDateString = (v) => typeof v === 'string' && v.length > 0 && !Number.isNaN(Date.parse(v));
Try / catch
try {
const result = renderDashboard({ now: raw });
} catch (err) {
if (err.message.startsWith('Invalid now timestamp')) {
console.error(`Bad --now value '${raw}'; using current time.`);
return renderDashboard({});
}
throw err;
} Prevention
- Always store/serialize timestamps as ISO 8601 (toISOString()).
- Parse CLI date flags with new Date(raw) and check for Invalid Date at the argument-parsing boundary.
- Never pass Date instances where an ISO string is expected.
When it happens
Trigger: Calling renderDashboard({ now: 'not-a-date' }); passing a locale-formatted date like '15/03/2026' that Date.parse cannot read; passing a Date object instead of an ISO string (Date.parse(Date) coerces oddly/NaN); passing undefined-like strings ('null', 'undefined') from CLI flags.
Common situations: Wiring a CLI --now flag straight from process.argv into options.now; env vars containing human-readable dates; tests injecting fixtures with accidentally invalid timestamps; timezone-specific formats on different machines.
Related errors
- Invalid now timestamp
- must be an ISO-8601 timestamp.
- recorded_at must be an ISO timestamp
- Unknown panel: . Valid panels
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/4ac15f43d6f9f2aa.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/skill-evolution/dashboard.js:335
for (const version of skill.versions) {
const date = version.created_at ? version.created_at.slice(0, 10) : '-';
const reason = version.reason || '-';
lines.push(` v${version.version} \u2500\u2500 ${date} \u2500\u2500 ${reason}`);
}
}
}
return {
text: panelBox('Version History', lines, width),
data: { skills: skillVersions },
};
}
function renderDashboard(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 dashboardOptions = { ...options, now };
const records = tracker.readSkillExecutionRecords(dashboardOptions);
const skillsById = health.discoverSkills(dashboardOptions);
const report = health.collectSkillHealth(dashboardOptions);
const summary = health.summarizeHealthReport(report);
const panelRenderers = {
'success-rate': () => renderSuccessRatePanel(records, report.skills, dashboardOptions),
'failures': () => renderFailureClusterPanel(records, dashboardOptions),
'amendments': () => renderAmendmentPanel(skillsById, dashboardOptions),
'versions': () => renderVersionTimelinePanel(skillsById, dashboardOptions),
};
const selectedPanel = options.panel || null;
if (selectedPanel && !VALID_PANELS.has(selectedPanel)) {
throw new Error(`Unknown panel: ${selectedPanel}. Valid panels: ${Array.from(VALID_PANELS).join(', ')}`);View on GitHub (pinned to 8321021c54)