CherryHQ/cherry-studio · warning · Error

Invalid nextThoughtNeeded: must be a boolean

Error message

Invalid nextThoughtNeeded: must be a boolean

What it means

The sequential-thinking server validates `nextThoughtNeeded` as a strict boolean (`typeof === 'boolean'`). Unlike the numeric fields it does NOT use a truthiness guard, so `0`/`1`/`"true"` are rejected. It throws a plain `Error`, returned as an `isError: true` tool result (not a thrown exception).

Source

Thrown at src/main/ai/mcp/servers/sequentialthinking.ts:42

class SequentialThinkingServer {
  private thoughtHistory: ThoughtData[] = []
  private branches: Record<string, ThoughtData[]> = {}

  private validateThoughtData(input: unknown): ThoughtData {
    const data = input as Record<string, unknown>

    if (!data.thought || typeof data.thought !== 'string') {
      throw new Error('Invalid thought: must be a string')
    }
    if (!data.thoughtNumber || typeof data.thoughtNumber !== 'number') {
      throw new Error('Invalid thoughtNumber: must be a number')
    }
    if (!data.totalThoughts || typeof data.totalThoughts !== 'number') {
      throw new Error('Invalid totalThoughts: must be a number')
    }
    if (typeof data.nextThoughtNeeded !== 'boolean') {
      throw new Error('Invalid nextThoughtNeeded: must be a boolean')
    }

    return {
      thought: data.thought,
      thoughtNumber: data.thoughtNumber,
      totalThoughts: data.totalThoughts,
      nextThoughtNeeded: data.nextThoughtNeeded,
      isRevision: data.isRevision as boolean | undefined,
      revisesThought: data.revisesThought as number | undefined,
      branchFromThought: data.branchFromThought as number | undefined,
      branchId: data.branchId as string | undefined,
      needsMoreThoughts: data.needsMoreThoughts as boolean | undefined
    }
  }

  private formatThought(thoughtData: ThoughtData): string {
    const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } =
      thoughtData

View on GitHub (pinned to 726446b54c)

Solutions

  1. Always pass a real boolean: `{ nextThoughtNeeded: false }` on the final thought.
  2. Ensure your client does not stringify/numericize booleans before sending.
  3. Set `false` only when the chain is truly complete.

Example fix

// before
{ nextThoughtNeeded: "true", ... }
// after
{ nextThoughtNeeded: true, ... }
Defensive patterns

Strategy: type-guard

Validate before calling

function asStrictBoolean(v: unknown): boolean {
  if (typeof v === 'boolean') return v
  throw new TypeError("'nextThoughtNeeded' must be a strict boolean (not 0/1/'true')")
}

Type guard

const isStrictBoolean = (v: unknown): v is boolean => typeof v === 'boolean'

Try / catch

const result = await client.callTool({ name: 'sequentialthinking', arguments: { ...raw, nextThoughtNeeded: asStrictBoolean(raw.nextThoughtNeeded) } })
if (result.isError) {
  const body = JSON.parse((result.content[0] as any).text)
  if (/nextThoughtNeeded/.test(body.error)) {/* pass a real boolean */}
}

Prevention

When it happens

Trigger: Submitting `nextThoughtNeeded` as a truthy non-boolean: `1`, `0`, `"true"`, `"false"`, or omitted (undefined fails typeof).

Common situations: A JSON serializer coerces booleans to integers/strings; the model emits `"true"`; the field is omitted on the final thought.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/71fbd3a4bc38b8dd. Report an issue: GitHub.