{"record":{"id":"df886c2359e5ec2b","repo":"coleam00/Archon","slug":"node-node-id-has-persist-session-true-but-re","errorCode":null,"errorMessage":"Node '${node.id}' has persist_session: true but resolved provider '${provider}' does not support sessionResume. Remove persist_session, or use a provider with sessionResume capability.","messagePattern":"Node '(.+?)' has persist_session: true but resolved provider '(.+?)' does not support sessionResume\\. Remove persist_session, or use a provider with sessionResume capability\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/workflows/src/dag-executor.ts","lineNumber":10499,"sourceCode":"                  'dag.session_provider_boundary_fresh'\n                );\n              }\n            }\n\n            // Strictly opt-in: on only when the node sets persist_session (or inherits the\n            // workflow-level persist_sessions default) and doesn't opt out via context:'fresh'.\n            // A parallel-layer node CAN still use persist_session — it just doesn't share\n            // with siblings. Same predicate gates the scope-artifact mirror below.\n            const usesPersistedScope = nodeUsesPersistedScope(node, ctx.workflowPersistSessions);\n\n            if (usesPersistedScope) {\n              // Runtime capability guard via the resolved provider instance (catches the\n              // case where provider was resolved from .archon/config.yaml defaults).\n              // Uses the instance's getCapabilities() rather than the static registry so\n              // tests can substitute mock providers with different caps without registering.\n              const caps = ctx.deps.getAgentProvider(provider).getCapabilities();\n              if (!caps.sessionResume) {\n                throw new Error(\n                  `Node '${node.id}' has persist_session: true but resolved provider '${provider}' does not support sessionResume. Remove persist_session, or use a provider with sessionResume capability.`\n                );\n              }\n              if (ctx.persistScopeKey && !hasNamedSessionResume) {\n                try {\n                  const persisted = await ctx.deps.store.getWorkflowNodeSession({\n                    workflow_name: ctx.workflowName,\n                    node_id: node.id,\n                    scope_key: ctx.persistScopeKey,\n                    provider,\n                  });\n                  if (persisted) {\n                    resumeSessionId = persisted.provider_session_id;\n                    // workflow_events is broader-scoped and longer-lived than the\n                    // node-session table. A session ID can resume a conversation, so we\n                    // store only an 8-char prefix here — enough for observability without\n                    // leaving a resumable artifact in the event log.\n                    const sessionIdPreview = `${persisted.provider_session_id.slice(0, 8)}…`;","sourceCodeStart":10481,"sourceCodeEnd":10517,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/workflows/src/dag-executor.ts#L10481-L10517","documentation":"A node declaring persist_session: true requires the resolved provider to support sessionResume, since persistence is meaningless without resumable sessions. The check runs against the live provider instance's getCapabilities() (not the static registry) so it also catches providers resolved from .archon/config.yaml defaults; when the capability is missing, the executor throws with an actionable message.","triggerScenarios":"A node sets persist_session: true while its resolved provider (node field, AI profile, or config default) reports sessionResume: false in getCapabilities(); common with mock/test providers or newly added providers lacking session support.","commonSituations":"Adding persist_session to a node while the global config default provider has no session support; tests substituting a mock provider without sessionResume; provider alias resolving to a different implementation than expected.","solutions":["Remove persist_session: true from the node if session continuity is not needed","Switch the node (or the config default) to a provider with sessionResume: true, e.g. claude","Implement sessionResume in the custom/mock provider's getCapabilities() if it genuinely supports sessions","Log the resolved provider for the node to confirm which provider the guard saw (it may come from config defaults, not the node field)"],"exampleFix":"// before\n- id: draft\n  prompt: \"...\"\n  persist_session: true\n  provider: simple-llm\n// after: drop persistence or use a resumable provider\n- id: draft\n  prompt: \"...\"\n  provider: claude\n  persist_session: true","handlingStrategy":"validation","validationCode":"const caps = ctx.deps.getAgentProvider(resolvedProvider).getCapabilities();\nif (node.persist_session && !caps.sessionResume) throw new Error(`${resolvedProvider} lacks sessionResume; remove persist_session or switch provider`);","typeGuard":"function canPersistSessions(caps: ProviderCapabilities): boolean {\n  return caps.sessionResume === true;\n}","tryCatchPattern":"try {\n  await engine.run(workflow);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('does not support sessionResume')) {\n    // drop persist_session or change the provider/default config\n  } else throw err;\n}","preventionTips":["Only add persist_session when the provider explicitly supports resume","Remember provider resolution order: node field > aiProfile > config defaults — check what actually resolves","In tests, ensure substituted mock providers declare sessionResume when nodes persist sessions"],"tags":["provider-capabilities","persist-session","workflow-config"],"backgroundTag":"unsupported-provider-capability","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}