nexu-io/open-design · warning · Error
${field} must be an object
Error message
${field} must be an object What it means
readAnswerRecord guards the answers argument. undefined is allowed (defaults to {}); any other non-object, null, or array is rejected. answers must be a plain record mapping question id to option id.
Source
Thrown at apps/daemon/src/mcp-brief.ts:655
if (value === undefined) return 'Untitled Open Design artifact';
const title = readRequiredString(value, 'projectTitle').trim();
if (title.length > 256) {
throw new Error('projectTitle must be at most 256 characters');
}
return title;
}
function readRequiredString(value: unknown, field: string): string {
if (typeof value !== 'string' || value.length === 0) {
throw new Error(`${field} must be a non-empty string`);
}
return value;
}
function readAnswerRecord(value: unknown, field: string): UnknownRecord {
if (value === undefined) return {};
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`${field} must be an object`);
}
return { ...(value as UnknownRecord) };
}
function stableAnswerDigest(answers: OpenDesignBriefAnswers): string {
return JSON.stringify(
Object.entries(answers)
.sort(([left], [right]) => left.localeCompare(right))
.map(([key, value]) => [key, [...value]]),
);
}
View on GitHub (pinned to 5be4028344)
Solutions
- Pass answers as a plain object such as { 'website.goal': 'launch-product' }.
- If you stringified it, parse it first.
- Convert array forms to a record before calling.
Example fix
// before
confirm_brief({ briefDraftId, nonce, answers: JSON.stringify(answers) })
// after
confirm_brief({ briefDraftId, nonce, answers: { 'website.goal': 'launch-product' } }) Defensive patterns
Strategy: type-guard
Validate before calling
if (answers != null && (typeof answers !== 'object' || Array.isArray(answers))) {
throw new Error('answers must be an object');
} Type guard
function isAnswerRecord(v: unknown): v is Record<string, string> {
return v == null || (typeof v === 'object' && !Array.isArray(v));
} Prevention
- Keep answers as a record keyed by question id, never a stringified blob or array.
- Parse any transported JSON before submit.
- Convert LLM array forms to a record before calling confirm_brief.
When it happens
Trigger: Passing answers as a JSON string; passing an array of the form [{ id, value }]; passing null.
Common situations: The caller JSON.stringify'd answers and forgot to parse; an LLM returned an array form.
Related errors
- pluginWorkflowId requires a validated externalPluginContext
- The Open Design brief is incomplete. Missing: ${missing.join
- artifactType must be one of: ${Object.keys(openDesignBriefCa
- projectTitle must be at most 256 characters
- ${field} must be a non-empty string
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/bf38b28f9bddedcc.
Report an issue: GitHub.