CopilotKit/CopilotKit · warning

[CopilotKit] Tool arguments parsed to non-object (${typeof p

Error message

[CopilotKit] Tool arguments parsed to non-object (${typeof parsed}), falling back to empty object

What it means

While streaming agent output, CopilotKit accumulates tool-call argument fragments and parses them with JSON.parse once complete. If the parsed value is not a plain object (e.g. the model emitted a bare string, number, boolean, or array as arguments), the runtime client warns and substitutes an empty object so downstream rendering does not crash. The message includes the actual typeof the parsed value.

Source

Thrown at packages/runtime-client-gql/src/client/conversion.ts:252

          status: item.status || { code: MessageStatusCode.Success },
        }),
      );
    }
  }
  return result;
}

function getPartialArguments(args: string[]) {
  try {
    if (!args.length) return {};

    const parsed = JSON.parse(untruncateJson(args.join("")));
    if (
      typeof parsed !== "object" ||
      parsed === null ||
      Array.isArray(parsed)
    ) {
      console.warn(
        `[CopilotKit] Tool arguments parsed to non-object (${typeof parsed}), falling back to empty object`,
      );
      return {};
    }
    return parsed;
  } catch (e) {
    // Incomplete JSON is expected during streaming — no warning needed
    return {};
  }
}

View on GitHub (pinned to 68fbe97d87)

Solutions

  1. Inspect the logged typeof to see what the model actually sent; if arguments are intentionally scalar, wrap them in an object on the agent side (e.g. {value: ...})
  2. Improve the tool's parameter schema/definitions so the model emits an object; ensure the tool handler tolerates an empty {} fallback
  3. If it happens only mid-stream, treat it as transient partial-JSON noise and ignore the warning; only act on the final message
  4. Switch to a stronger model if malformed arguments recur

Example fix

// agent tool definition (before): arguments emitted as a bare string
// after: force object-shaped arguments
const tool = {
  name: "echo",
  parameters: { type: "object", properties: { text: { type: "string" } }, required: ["text"] },
};
Defensive patterns

Strategy: validation

Validate before calling

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null && !Array.isArray(v);
}

Type guard

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
  typeof v === "object" && v !== null && !Array.isArray(v);

Prevention

When it happens

Trigger: An LLM streams tool arguments that parse to a JSON scalar or array, e.g. '"hello world"', '42', 'true', or '[1,2,3]' inside a streaming tool call handled by convertGqlOutputToMessages -> getPartialArguments. Also occurs when untruncation of a partially-streamed JSON produces a non-object like an empty string.

Common situations: Weak models or low temperature misconfiguration producing malformed tool arguments; custom agents (LangGraph/CrewAI) that return non-object argument payloads; partially streamed JSON at message boundaries being untruncated to a scalar.

Related errors


AI-assisted analysis of CopilotKit/CopilotKit@68fbe97d87 (2026-08-27). Data as JSON: /api/errors/f42a1cdb53eefbee. Report an issue: GitHub.