tldraw/tldraw · error · Error
clusterIds is required: a cluster id, or an array of them
Error message
clusterIds is required: a cluster id, or an array of them
What it means
Thrown by parseClusterIds when value is not a string and not a non-empty array. parseClusterScreenshotInput calls it to validate the clusterIds argument for the take-cluster-screenshots MCP tool. A single string is accepted (wrapped into [value]) for convenience; anything else — undefined, null, an empty array, an object, a number — is rejected.
Source
Thrown at apps/dotcom/sync-worker/src/routes/tla/sharedBoardScreenshotMcp.ts:347
page: PageSelector
clusterIds: string[]
theme: 'light' | 'dark'
} {
const value = requireArgumentsObject(input)
return {
boardId: parseBoardId(value.boardId),
page: parsePageSelector(value.page),
clusterIds: parseClusterIds(value.clusterIds),
theme: parseTheme(value.theme),
}
}
// Accepts one id or several. A single string is allowed because asking for one cluster is the common
// case and making callers wrap it in an array is friction for nothing.
export function parseClusterIds(value: unknown): string[] {
if (typeof value === 'string') return [parseClusterId(value)]
if (!Array.isArray(value) || value.length === 0) {
throw new Error('clusterIds is required: a cluster id, or an array of them')
}
return value.map((id) => parseClusterId(id))
}
export function parseClusterId(value: unknown): string {
if (typeof value !== 'string' || value.length === 0) {
throw new Error('clusterId is required')
}
return value
}
function requireArgumentsObject(input: unknown): Record<string, unknown> {
if (!input || typeof input !== 'object') {
throw new Error('Tool arguments must be an object')
}
return input as Record<string, unknown>
}
View on GitHub (pinned to b31086b447)
Solutions
- Provide clusterIds as a single id string or an array of id strings: {"clusterIds":"abc"} or {"clusterIds":["abc","def"]}.
- If you have a comma-separated list, split it into an array before passing.
- Ensure every element is a non-empty string.
Example fix
// before
{ "clusterIds": "a,b,c" } // treated as one id, parseClusterId may reject
// after
{ "clusterIds": ["a","b","c"] } Defensive patterns
Strategy: validation
Validate before calling
function asClusterIds(value: unknown): string[] {
if (typeof value === 'string') return [value]
if (Array.isArray(value) && value.length > 0) return value.filter((v): v is string => typeof v === 'string' && v.length > 0)
throw new Error('clusterIds is required: a cluster id, or an array of them')
} Type guard
function isClusterIdsInput(value: unknown): value is string | string[] {
return typeof value === 'string' || (Array.isArray(value) && value.every((v) => typeof v === 'string' && v.length > 0) && value.length > 0)
} Prevention
- Pass clusterIds as a single id string or an array of id strings.
- Split comma-separated lists into arrays before sending.
- Filter out empty/null elements from arrays.
When it happens
Trigger: MCP tool call to take_cluster_screenshots (or parseClusterScreenshotInput directly) with clusterIds omitted, set to null, an empty array [], or a non-array non-string value. Each element must itself pass parseClusterId.
Common situations: LLM/caller omits clusterIds assuming a default; passes an array of objects instead of strings; passes a comma-separated string (which would be treated as one id and fail parseClusterId).
Related errors
- clusterId is required
- No tldraw account for: ${unknown.join(', ')}
- e instanceof Error ? e.message : String(e)
- User not found ${q}
- objectId must be a 64-char lowercase hex string
AI-assisted analysis of tldraw/tldraw@b31086b447 (2026-08-12).
Data as JSON: /api/errors/79e6864c6b41a8a8.
Report an issue: GitHub.