nexu-io/open-design · warning · Error
The Open Design brief has expired or is unknown. Call collec
Error message
The Open Design brief has expired or is unknown. Call collect_brief again.
What it means
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.
Source
Thrown at apps/daemon/src/mcp-brief.ts:438
expiresAt,
...(pluginWorkflowId ? { pluginWorkflowId } : {}),
...(externalPluginContext ? { externalPluginContext } : {}),
questionForm: questionFormsByLocale[locale],
questionFormsByLocale,
};
},
confirm(input) {
const at = now();
pruneExpired(at);
const briefDraftId = readRequiredString(
input.briefDraftId,
'briefDraftId',
);
const nonce = readRequiredString(input.nonce, 'nonce');
const draft = drafts.get(briefDraftId);
if (!draft) {
throw new Error(
'The Open Design brief has expired or is unknown. Call collect_brief again.',
);
}
if (draft.nonce !== nonce) {
throw new Error('The Open Design brief nonce is invalid.');
}
const submittedAnswers = readAnswerRecord(input.answers, 'answers');
const mergedAnswers: UnknownRecord = {
...draft.knownAnswers,
...submittedAnswers,
};
const decision = collectOpenDesignBrief({
artifactType: draft.artifactType,
knownAnswers: mergedAnswers,
});
if (!decision.complete) {
const missing = decision.questions.map((question) => question.id);
throw new Error(View on GitHub (pinned to 5be4028344)
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.
Example fix
// before
confirm_brief({ briefDraftId: staleId, nonce: staleNonce, answers }) // throws [360]
// after
const draft = await collect_brief({ artifactType: 'website' })
await confirm_brief({ briefDraftId: draft.briefDraftId, nonce: draft.nonce, answers }) Defensive patterns
Strategy: retry
Validate before calling
const draft = store.peek(briefDraftId);
if (!draft || Date.now() > draft.expiresAt) {
// draft gone or expired -> must re-collect
const fresh = await collectBrief({ artifactType });
return confirmBrief({ ...input, briefDraftId: fresh.briefDraftId, nonce: fresh.nonce });
} Try / catch
try {
await confirmBrief(input);
} catch (e) {
if (/expired or is unknown/i.test(e.message)) {
const fresh = await collectBrief({ artifactType });
return confirmBrief({ ...input, briefDraftId: fresh.briefDraftId, nonce: fresh.nonce });
}
throw e;
} Prevention
- Always pair confirm with the immediately preceding collect_brief output.
- Never cache briefDraftId across process or daemon restarts.
- Confirm within the brief TTL window.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- pluginWorkflowId requires a validated externalPluginContext
- The Open Design brief nonce is invalid.
- The Open Design brief is incomplete. Missing: ${missing.join
- This Open Design brief was already confirmed with different
- artifactType must be one of: ${Object.keys(openDesignBriefCa
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/fe50475bd37acb28.
Report an issue: GitHub.