{"record":{"id":"8e9d0a45886610a6","repo":"microsoft/semantic-kernel","slug":"openapi-tool-spec-id-is-missing-required-spec","errorCode":null,"errorMessage":"OpenAPI tool '{spec.id}' is missing required 'specification' field.","messagePattern":"OpenAPI tool '(.+?)' is missing required 'specification' field\\.","errorType":"validation","errorClass":"AgentInitializationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/agents/azure_ai/azure_ai_agent.py","lineNumber":208,"sourceCode":"            raise AgentInitializationException(f\"Function `{spec.id}` not found in kernel.\")\n        case 1:\n            return kernel_function_metadata_to_function_call_format(funcs[0])  # type: ignore[return-value]\n        case _:\n            raise AgentInitializationException(f\"Multiple definitions found for `{spec.id}`. Please remove duplicates.\")\n\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:","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/azure_ai/azure_ai_agent.py#L190-L226","documentation":"Raised by the OpenAPI tool builder when a declarative spec declares a tool of type 'openapi' but its options map has no 'specification' entry (or it is empty). The Azure AI OpenApiTool cannot be constructed without the OpenAPI document, so agent initialization is aborted. It surfaces as an AgentInitializationException during AzureAIAgent restore/create from a YAML/JSON spec.","triggerScenarios":"Calling AzureAIAgent restore/creation with a declarative spec that lists a tool {\"type\":\"openapi\",\"id\":\"x\"} but omits options.specification, or sets it to an empty string. Also triggered when the 'specification' key is misspelled (e.g. 'spec' or 'openapi_spec').","commonSituations":"Migrating from a hand-built OpenApiTool call to the declarative spec format and forgetting to inline the spec document; copying an example that loaded the spec from a file separately; YAML indentation that collapses the specification under the wrong key.","solutions":["Add an 'options.specification' field to the openapi tool entry containing the full OpenAPI document (a JSON string or a parsed object).","Verify the key is exactly 'specification' and is nested under 'options', not at the tool top level.","If loading from a file, read its contents and pass them as options.specification before building the agent.","Run the spec through AzureAIAgent.resolve_placeholders first to confirm the structure is intact."],"exampleFix":"// before\ntools:\n  - type: openapi\n    id: weather\n    description: weather api\n// after\ntools:\n  - type: openapi\n    id: weather\n    description: weather api\n    options:\n      specification: |\n        {\"openapi\":\"3.0.0\",\"paths\":{...}}","handlingStrategy":"validation","validationCode":"def validate_openapi_tool(spec_dict):\n    for t in spec_dict.get('tools', []):\n        if t.get('type') == 'openapi':\n            opts = t.get('options') or {}\n            if not opts.get('specification'):\n                raise ValueError(f\"openapi tool '{t.get('id')}' missing options.specification\")\n    return spec_dict\n# call before AzureAIAgent restore/create","typeGuard":"def has_openapi_spec(tool_entry: dict) -> bool:\n    return (\n        tool_entry.get('type') == 'openapi'\n        and bool((tool_entry.get('options') or {}).get('specification'))\n    )","tryCatchPattern":"try:\n    agent = await AzureAIAgent._from_dict(data, kernel=kernel, client=client)\nexcept AgentInitializationException as e:\n    if 'specification' in str(e):\n        log.error('OpenAPI tool missing specification; check options.specification')\n    raise","preventionTips":["Validate the spec dict with a small schema check before passing to _from_dict.","Keep OpenAPI specs in JSON files and load them into options.specification programmatically.","Add unit tests that assert every openapi tool has a non-empty specification."],"tags":["azure-ai","openapi","declarative-spec","configuration","agent-initialization"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}