OpenAI Function Arguments Parse Error — Fix (2026) | AI Error Hub
OpenAIFunction CallingSeverity: LowClient-side

OpenAI Function Arguments Parse Error

Your code treated tool_call.function.arguments as an object but it's a JSON string. Always JSON.parse() / json.loads() before use. This is by design — arguments arrive as a raw string to preserve the model's exact output.

Error surface: Type mismatchCategory: Function CallingCommon in: New OpenAI integrationsLast tested: Nov 15, 2026
Quick Fix (TL;DR)

Parse arguments as JSON before using: args = JSON.parse(tool_call.function.arguments). It's a string by design. Wrap in try/catch (with strict mode off) or use SDK helpers that auto-parse. Enable strict: true to guarantee valid JSON.

The Symptoms You're Seeing

Common type errors
Python:
  args = tool_call.function.arguments
  location = args["location"]
  → TypeError: string indices must be integers, not 'str'

TypeScript:
  const args = tool_call.function.arguments;
  const location = args.location;
  → undefined (accessing property on string returns undefined)
  → or: Property 'location' does not exist on type 'string'

Console log shows:
  args: '{"location":"Karachi","units":"celsius"}'
  ← that's a STRING, not object

Why arguments Is a String

Design rationale

OpenAI returns arguments as a raw string to preserve the model's exact output. If arguments were pre-parsed to an object, invalid JSON would raise inside the SDK; the string form lets your code inspect and repair before parsing. Once you enable strict: true, the string is guaranteed valid, but it's still a string.

Response structure
response.choices[0].message.tool_calls[0] = { id: "call_abc123", "type": "function", function: { name: "get_weather", arguments: '{"location":"Karachi","units":"celsius"}' // ↑ this is a STRING } }

What Actually Causes This Error

55%
Assumed arguments is an objectDirect property access without parsing.
22%
SDK version confusionDifferent SDKs handle this differently; some auto-parse, some don't.
12%
Migration from legacy function_call formatOld function_call.arguments was also a string; developers forget in refactor.
7%
Type annotations misledCustom types marking arguments as Record<string, unknown> without parsing.
4%
Streaming assembly missed final parseConcatenated chunks but forgot to parse the final assembled string.

Fixes That Work (Tested Nov 2026)

1Parse Explicitly Every Time

Python · correct parsing
import json response = client.chat.completions.create(...) message = response.choices[0].message if message.tool_calls: for tool_call in message.tool_calls: if tool_call.type == "function": name = tool_call.function.name # ALWAYS parse the string args = json.loads(tool_call.function.arguments) # Now args is a dict — use safely if name == "get_weather": result = get_weather(args["location"], args["units"])
TypeScript · with type safety
import OpenAI from "openai"; const client = new OpenAI(); interface WeatherArgs { location: string; units: "celsius" | "fahrenheit"; } const response = await client.chat.completions.create({...}); const message = response.choices[0].message; if (message.tool_calls) { for (const tc of message.tool_calls) { if (tc.type === "function") { // Parse then type-assert const args: WeatherArgs = JSON.parse(tc.function.arguments); const weather = await getWeather(args.location, args.units); } } }

2Safe Parser Helper

Python · reusable parse helper
import json from typing import Any def parse_tool_args(tool_call) -> dict: """Parse tool_call arguments with defensive handling.""" args_str = tool_call.function.arguments if not args_str: return {} # empty function call if isinstance(args_str, dict): # Some SDKs pre-parse — handle both return args_str try: return json.loads(args_str) except json.JSONDecodeError as e: raise ValueError( f"Function {tool_call.function.name} returned invalid JSON: " f"{args_str[:100]}" ) from e # Use everywhere for tc in message.tool_calls: args = parse_tool_args(tc) result = dispatch_function(tc.function.name, args)

3Streaming Assembly (must parse at end)

Python · streaming with parse at completion
import json from collections import defaultdict stream = client.chat.completions.create(..., stream=True) # Accumulate tool_call chunks by index tool_calls_by_index = defaultdict(lambda: { "id": None, "name": None, "args_buffer": "" }) for chunk in stream: for tc_delta in chunk.choices[0].delta.tool_calls or []: idx = tc_delta.index tc = tool_calls_by_index[idx] if tc_delta.id: tc["id"] = tc_delta.id if tc_delta.function: if tc_delta.function.name: tc["name"] = tc_delta.function.name if tc_delta.function.arguments: tc["args_buffer"] += tc_delta.function.arguments # After stream ends, parse each accumulated string for idx, tc in tool_calls_by_index.items(): args = json.loads(tc["args_buffer"]) # parse the string dispatch(tc["name"], args)

Preventing This Error Going Forward

  • Always json.loads(tc.function.arguments). String → dict. No exceptions.
  • Create a parse helper and use it everywhere. Central point of correctness.
  • Type your dispatchers with parsed args. Interfaces enforce the parsing step.
  • In streaming, accumulate strings then parse at end. Never parse partial JSON.
  • Enable strict: true. Guarantees the string parses successfully.
AR
Tested by Ahmed R.
Researcher · AI Error Hub
Last verified: Nov 15, 2026 · SDK: openai 1.54

Frequently Asked Questions

Some ORM-style libraries built on top of OpenAI (instructor, marvin) auto-parse. The official OpenAI SDK returns raw strings by design. Check your specific SDK's docs.

Same behavior — arguments is a string on tool_call submission. Parse the same way. Consistent across chat.completions and beta.threads endpoints.

Yes, for functions with no parameters. arguments = "{}". Still a string, still parseable. Handle empty dict result in your dispatcher.

Wrap in try/except. Log the raw arguments string for debugging. Consider retry with more specific instructions or migrate to strict mode.

No — Claude returns tool_use.input as a parsed object directly. This is OpenAI-specific behavior. When porting code, watch for this difference.