{"record":{"id":"bb268f170f506b2a","repo":"NousResearch/hermes-agent","slug":"preview-mode-launching-is-disabled","errorCode":null,"errorMessage":"Preview mode — launching is disabled.","messagePattern":"Preview mode — launching is disabled\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/bootstrap-installer/src/store.ts","lineNumber":351,"sourceCode":"  // there's no welcome click. Reset + jump straight to progress, then let the\n  // Rust side stream the synthetic update manifest.\n  $bootstrap.set(INITIAL)\n  $route.set('progress')\n  await invoke('start_update')\n}\n\nexport async function cancelInstall(): Promise<void> {\n  if (fakeMode()) {\n    fakeCancelled = true\n\n    return\n  }\n\n  await invoke('cancel_bootstrap')\n}\n\nexport async function launchHermesDesktop(): Promise<void> {\n  if (fakeMode()) {throw new Error('Preview mode — launching is disabled.')}\n  const installRoot = $bootstrap.get().installRoot\n\n  if (!installRoot) {throw new Error('no install root')}\n  await invoke('launch_hermes_desktop', { installRoot })\n}\n\nexport async function openLogDir(): Promise<void> {\n  if (fakeMode()) {return}\n  await invoke('open_log_dir')\n}\n\n// ---------------------------------------------------------------------------\n// Dev-only isolated preview (\"fake boot\")\n//\n// Synthesises the manifest + stage/log events Rust normally streams, so the\n// whole reskin can be reviewed in a plain browser (`npm run dev`):\n//   ?fake=install   welcome → [ INSTALL ] → success\n//   ?fake=update    auto-runs the granular update flow","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/bootstrap-installer/src/store.ts#L333-L369","documentation":"Raised by the schedule parser in cron/jobs.py when a schedule string starts with something that looks like an ISO timestamp (e.g. begins with a digit and contains 'T'/'-') but datetime.fromisoformat() rejects it. It is a ValueError wrapping the underlying parse failure, thrown before any job is created. The full schedule-format dispatch continues to duration/interval/cron parsing afterwards, so this error alone does not abandon the parse.","triggerScenarios":"Calling create_job/update_job (or the cronjob tool / `hermes cron add`) with a schedule like '2026-13-45T99:00' (invalid month/hour), '2026-02-30T14:00' (nonexistent day), or a malformed timestamp with stray characters that still routes into the timestamp branch of the parser.","commonSituations":"Typos in one-shot timestamps, copy-pasting timestamps with a trailing 'Z' variant the parser's branch does not accept, or a model/agent composing the schedule string dynamically and getting the date arithmetic wrong (e.g. month 13).","solutions":["Correct the timestamp to a valid ISO 8601 local form such as '2026-02-03T14:00:00'.","If you wanted a relative one-shot, use a duration like '30m', '2h', '1d' instead.","Read the wrapped {e} message — it names the exact reason fromisoformat rejected the value.","Validate candidate timestamps with datetime.fromisoformat() before submitting if generating schedules programmatically."],"exampleFix":"# before\ncreate_job(prompt=\"report\", schedule=\"2026-02-30T14:00\")\n\n# after\ncreate_job(prompt=\"report\", schedule=\"2026-03-02T14:00\")","handlingStrategy":"validation","validationCode":"from datetime import datetime\n\ndef valid_timestamp(s: str) -> bool:\n    try:\n        datetime.fromisoformat(s)\n        return True\n    except ValueError:\n        return False\n\n# before create_job(..., schedule=\"2026-02-30T14:00\")\nassert valid_timestamp(\"2026-02-30T14:00\") is False","typeGuard":null,"tryCatchPattern":"from cron.jobs import create_job\ntry:\n    job = create_job(prompt=p, schedule=\"2026-02-30T14:00\")\nexcept ValueError as e:\n    if \"Invalid timestamp\" in str(e):\n        # surface to user / re-ask model for a corrected ISO string\n        raise","preventionTips":["Generate timestamps with datetime.now() + timedelta and .isoformat(), never by string concatenation.","If schedules come from LLM output, pre-validate against all four accepted forms before calling create_job."],"tags":["cron","schedule","validation","valueerror"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}