{"record":{"id":"35b5751754398c4b","repo":"sinelaw/fresh","slug":"action-failed","errorCode":null,"errorMessage":"${action} failed","messagePattern":"(.+?) failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/plugins/orchestrator.ts","lineNumber":10704,"sourceCode":"  refreshOpenDialog();\n  return true;\n}\n\n/// Archive / delete over a single workspace, through the same batch runner\n/// the picker's confirmed action uses — so the cross-machine manifest sync,\n/// and anything added to that path later, applies to a scripted archive too.\nasync function runLifecycle(\n  target: string | number,\n  action: \"archive\" | \"delete\",\n): Promise<boolean> {\n  // Before `requireEligible`, which rejects an ineligible workspace.\n  await yieldToCaller();\n  const s = resolveWorkspace(target);\n  if (!s) return false;\n  requireEligible(s, action);\n  const res = await runLifecycleBatch(action, [s.id]);\n  if (res.ok === 0) {\n    throw new Error(res.lastErr || `${action} failed`);\n  }\n  refreshOpenDialog();\n  return true;\n}\n\nfunction apiListArchived(): ArchivedWorkspace[] {\n  const out: ArchivedWorkspace[] = [];\n  for (const { manifest } of scanArchiveManifests()) {\n    for (const e of manifest.sessions) {\n      out.push({\n        archivedRoot: e.root,\n        originalRoot: e.original_root,\n        name: e.label,\n        branch: e.branch,\n        archivedAt: e.archived_at,\n        projectPath: e.repo_root ?? \"\",\n      });\n    }","sourceCodeStart":10686,"sourceCodeEnd":10722,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/plugins/orchestrator.ts#L10686-L10722","documentation":"The single-workspace archive/delete API runs the action through runLifecycleBatch and throws when the batch reports zero successes. It prefers res.lastErr — the real underlying error from the batch — and only falls back to the generic '${action} failed' message when no detail is available. Seeing the generic message means the batch failed without reporting a cause.","triggerScenarios":"Calling the archive or delete verb for one workspace when runLifecycleBatch returns { ok: 0 } with no lastErr — e.g. a cross-machine manifest sync failure or an internal batch error without a recorded message.","commonSituations":"Manifest sync conflicts between machines; transient storage errors during archive/delete; calling with a workspace that passed eligibility but fails during actual processing.","solutions":["Read res.lastErr from the batch result if available — prefer the API path that surfaces it for diagnosis","Retry the action after a short delay if the cause was a transient sync issue","Verify the workspace state (already archived/deleted?) and skip if the action effectively completed"],"exampleFix":"// before\nawait api.archiveWorkspace(id);\n// after\ntry {\n  await api.archiveWorkspace(id);\n} catch (e) {\n  console.warn(\"archive failed:\", e);\n  await new Promise(r => setTimeout(r, 1000));\n  await api.archiveWorkspace(id); // retry transient failures\n}","handlingStrategy":"retry","validationCode":"const ws = api.getWorkspace(id);\nif (!ws) return false; // avoid calling lifecycle on a vanished workspace","typeGuard":null,"tryCatchPattern":"try {\n  await api.archiveWorkspace(id);\n} catch (e) {\n  const msg = String(e);\n  if (msg.endsWith(\"archive failed\") || msg.endsWith(\"delete failed\")) {\n    await new Promise(r => setTimeout(r, 1000));\n    await api.archiveWorkspace(id); // retry once; no lastErr detail available\n  } else throw e;\n}","preventionTips":["Prefer error paths that surface res.lastErr for diagnostics","Retry only once with backoff — the generic message means the cause is unknown","Re-check workspace state after failure (action may have partially completed)","Ensure manifest sync is healthy (single-machine or synced) before lifecycle verbs"],"tags":["typescript","lifecycle","batch-operation"],"backgroundTag":"operation-failed","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}