{"record":{"id":"01235b8e33bb47de","repo":"microsoft/semantic-kernel","slug":"invalid-json-in-openapi-specification-field-e","errorCode":null,"errorMessage":"Invalid JSON in OpenAPI 'specification' field: {e}","messagePattern":"Invalid JSON in OpenAPI 'specification' field: (.+?)","errorType":"validation","errorClass":"AgentInitializationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/agents/azure_ai/azure_ai_agent.py","lineNumber":213,"sourceCode":"\n\n@_register_tool(\"openapi\")\ndef _openapi(spec: ToolSpec) -> OpenApiTool:\n    opts = spec.options or {}\n\n    if not spec.id:\n        raise AgentInitializationException(\"OpenAPI tool requires a non-empty 'id' (used as name).\")\n    if not spec.description:\n        raise AgentInitializationException(f\"OpenAPI tool '{spec.id}' requires a 'description'.\")\n\n    raw_spec = opts.get(\"specification\")\n    if not raw_spec:\n        raise AgentInitializationException(f\"OpenAPI tool '{spec.id}' is missing required 'specification' field.\")\n\n    try:\n        parsed_spec = json.loads(raw_spec) if isinstance(raw_spec, str) else raw_spec\n    except json.JSONDecodeError as e:\n        raise AgentInitializationException(f\"Invalid JSON in OpenAPI 'specification' field: {e}\") from e\n\n    auth = opts.get(\"auth\", OpenApiAnonymousAuthDetails())\n\n    return OpenApiTool(\n        name=spec.id,\n        description=spec.description,\n        spec=parsed_spec,\n        auth=auth,\n        default_parameters=opts.get(\"default_parameters\"),\n    )\n\n\ndef _build_tool(spec: ToolSpec, kernel: \"Kernel\") -> ToolDefinition:\n    if not spec.type:\n        raise AgentInitializationException(\"Tool spec must include a 'type' field.\")\n\n    try:\n        builder = _TOOL_BUILDERS[spec.type.lower()]","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/azure_ai/azure_ai_agent.py#L195-L231","documentation":"Raised when the OpenAPI tool's 'specification' option is a string but json.loads fails to parse it. The builder first tries to parse strings as JSON (passing objects through unchanged), so this only fires for malformed JSON text. The original JSONDecodeError is chained as the cause for debugging.","triggerScenarios":"Passing options.specification as a string that contains YAML instead of JSON; a string with trailing commas, single quotes, or comments; a truncated/copy-pasted spec string; a file read that included a BOM or surrounding whitespace/newlines that break strict JSON.","commonSituations":"Authoring the OpenAPI doc by hand as a string literal and using YAML/JS-style syntax; loading a .yaml OpenAPI file into the string field instead of converting it to JSON; embedding a JSON string with f-string interpolation that introduced stray characters.","solutions":["Validate the specification string with a JSON linter (e.g. python -m json.tool) before passing it.","If your source is YAML, parse it first (yaml.safe_load) and pass the resulting dict, not the raw YAML text.","Pass the specification as a pre-parsed dict/object to bypass string parsing entirely.","Inspect the chained exception 'e' (position/column) to locate the syntax error."],"exampleFix":"// before\noptions:\n  specification: \"openapi: 3.0.0\\npaths: /weather\"  # YAML, not JSON\n// after\nimport yaml, json\nspec = yaml.safe_load(open('openapi.yaml'))\noptions = {\"specification\": json.dumps(spec)}  # or pass spec dict directly","handlingStrategy":"validation","validationCode":"import json\ndef ensure_valid_json_specification(opts):\n    spec = opts.get('specification')\n    if isinstance(spec, str):\n        json.loads(spec)  # raises early with a clear error\n    return spec\n# call on each openapi tool's options before agent creation","typeGuard":"def is_json_or_object(v) -> bool:\n    if not isinstance(v, str):\n        return isinstance(v, (dict, list))\n    try:\n        json.loads(v); return True\n    except json.JSONDecodeError:\n        return False","tryCatchPattern":"try:\n    agent = await AzureAIAgent._from_dict(data, kernel=kernel, client=client)\nexcept AgentInitializationException as e:\n    cause = e.__cause__\n    if isinstance(cause, json.JSONDecodeError):\n        log.error('Malformed JSON specification at line %s col %s', cause.lineno, cause.colno)\n    raise","preventionTips":["Prefer passing the specification as a parsed dict/object to avoid string-parsing pitfalls.","If sourcing from YAML, parse with yaml.safe_load first and pass the resulting object.","Lint JSON specification strings with python -m json.tool before embedding them."],"tags":["azure-ai","openapi","json","parsing","configuration"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}