{"record":{"id":"fe50475bd37acb28","repo":"nexu-io/open-design","slug":"the-open-design-brief-has-expired-or-is-unknown-c","errorCode":null,"errorMessage":"The Open Design brief has expired or is unknown. Call collect_brief again.","messagePattern":"The Open Design brief has expired or is unknown\\. Call collect_brief again\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/daemon/src/mcp-brief.ts","lineNumber":438,"sourceCode":"        expiresAt,\n        ...(pluginWorkflowId ? { pluginWorkflowId } : {}),\n        ...(externalPluginContext ? { externalPluginContext } : {}),\n        questionForm: questionFormsByLocale[locale],\n        questionFormsByLocale,\n      };\n    },\n\n    confirm(input) {\n      const at = now();\n      pruneExpired(at);\n      const briefDraftId = readRequiredString(\n        input.briefDraftId,\n        'briefDraftId',\n      );\n      const nonce = readRequiredString(input.nonce, 'nonce');\n      const draft = drafts.get(briefDraftId);\n      if (!draft) {\n        throw new Error(\n          'The Open Design brief has expired or is unknown. Call collect_brief again.',\n        );\n      }\n      if (draft.nonce !== nonce) {\n        throw new Error('The Open Design brief nonce is invalid.');\n      }\n      const submittedAnswers = readAnswerRecord(input.answers, 'answers');\n      const mergedAnswers: UnknownRecord = {\n        ...draft.knownAnswers,\n        ...submittedAnswers,\n      };\n      const decision = collectOpenDesignBrief({\n        artifactType: draft.artifactType,\n        knownAnswers: mergedAnswers,\n      });\n      if (!decision.complete) {\n        const missing = decision.questions.map((question) => question.id);\n        throw new Error(","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/mcp-brief.ts#L420-L456","documentation":"Thrown by the local MCP brief store's confirm step when no in-memory draft exists for the supplied briefDraftId. Drafts live in a process-local Map pruned by expiresAt (TTL) on every confirm call, so any draft that aged out, was never created, or belonged to a previous daemon process is gone. The message directs the caller to start over with collect_brief, which mints a fresh briefDraftId and nonce.","triggerScenarios":"Calling confirm_brief after the draft TTL elapsed; calling it after a daemon restart (drafts are in-memory only and not persisted); passing a briefDraftId from a different Open Design MCP session; passing a typo or stale copied id.","commonSituations":"Long pause between collect_brief and confirm_brief in an agent loop exceeding the TTL; daemon auto-restarted mid-flow; two MCP clients each running their own brief and mixing ids.","solutions":["Call collect_brief again to obtain a new briefDraftId and nonce, then confirm immediately within the TTL.","Confirm in the same daemon process and same MCP session that created the draft.","When automating, keep collect then confirm in a tight sequence and never persist briefDraftId across restarts."],"exampleFix":"// before\nconfirm_brief({ briefDraftId: staleId, nonce: staleNonce, answers }) // throws [360]\n\n// after\nconst draft = await collect_brief({ artifactType: 'website' })\nawait confirm_brief({ briefDraftId: draft.briefDraftId, nonce: draft.nonce, answers })","handlingStrategy":"retry","validationCode":"const draft = store.peek(briefDraftId);\nif (!draft || Date.now() > draft.expiresAt) {\n  // draft gone or expired -> must re-collect\n  const fresh = await collectBrief({ artifactType });\n  return confirmBrief({ ...input, briefDraftId: fresh.briefDraftId, nonce: fresh.nonce });\n}","typeGuard":null,"tryCatchPattern":"try {\n  await confirmBrief(input);\n} catch (e) {\n  if (/expired or is unknown/i.test(e.message)) {\n    const fresh = await collectBrief({ artifactType });\n    return confirmBrief({ ...input, briefDraftId: fresh.briefDraftId, nonce: fresh.nonce });\n  }\n  throw e;\n}","preventionTips":["Always pair confirm with the immediately preceding collect_brief output.","Never cache briefDraftId across process or daemon restarts.","Confirm within the brief TTL window."],"tags":["mcp","brief","session-state","ttl"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}