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

  1. Pass a valid ISO 8601 string, e.g. renderDashboard({ now: new Date().toISOString() }).
  2. Coerce before calling: const nowMs = Date.parse(opts.now); if (Number.isNaN(nowMs)) fix/throw in the caller.
  3. If the value comes from a CLI flag, validate/parse it at the CLI boundary and report a friendly usage error.
  4. 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

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


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)