{"record":{"id":"ca05d56c61c9d029","repo":"microsoft/semantic-kernel","slug":"tool-spec-must-include-a-type-field-ca05d5","errorCode":null,"errorMessage":"Tool spec must include a 'type' field.","messagePattern":"Tool spec must include a 'type' field\\.","errorType":"exception","errorClass":"AgentInitializationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/agents/open_ai/openai_responses_agent.py","lineNumber":126,"sourceCode":"        score_threshold=score_threshold,\n        ranker=ranker,\n    )\n\n\n@_register_tool(\"web_search\")\ndef _web_search(spec: ToolSpec, kernel: Kernel | None = None) -> WebSearchToolParam:\n    options = spec.options or {}\n    context_size = options.get(\"search_context_size\")\n    user_location = options.get(\"user_location\")\n    return OpenAIResponsesAgent.configure_web_search_tool(\n        context_size=context_size,\n        user_location=user_location,\n    )\n\n\ndef _build_tool(spec: ToolSpec, kernel: \"Kernel\") -> ToolParam:\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()]\n    except KeyError as exc:\n        raise AgentInitializationException(f\"Unsupported tool type: {spec.type}\") from exc\n\n    sig = inspect.signature(builder)\n    return builder(spec) if len(sig.parameters) == 1 else builder(spec, kernel)  # type: ignore[call-arg]\n\n\n# endregion\n\n\n# region Agent Thread\n\n\n@experimental\nclass ResponsesAgentThread(AgentThread):","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/open_ai/openai_responses_agent.py#L108-L144","documentation":"Raised by _build_tool() in openai_responses_agent when a ToolSpec has a falsy type attribute. The tool dispatch table is keyed by spec.type.lower(); a missing/empty type means no builder can be selected, so the library rejects it rather than throwing a confusing KeyError.","triggerScenarios":"A declarative tool entry without a 'type' field, or with type set to ''/None; a YAML tool block that is an empty mapping; deserializing a partial tool spec.","commonSituations":"Hand-authored YAML tool list with a tool missing its type; programmatic spec construction that omits type; schema change where type became optional but the runtime still requires it.","solutions":["Ensure every tool spec has a non-empty 'type' matching a registered builder (file_search, web_search).","Validate ToolSpec.type is truthy before calling _build_tool / before adding to spec.tools.","Drop malformed tool entries from the spec before agent creation."],"exampleFix":"# before\ntool_spec = {'options': {'vector_store_ids': ['vs_x']}}\n\n# after\ntool_spec = {'type': 'file_search', 'options': {'vector_store_ids': ['vs_x']}}","handlingStrategy":"validation","validationCode":"assert spec.get('type'), 'tool spec must include a non-empty type'","typeGuard":"def tool_spec_has_type(spec: dict) -> bool:\n    return bool(spec.get('type'))","tryCatchPattern":"from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException\ntry:\n    tool = _build_tool(tool_spec, kernel)\nexcept AgentInitializationException as e:\n    if \"'type' field\" in str(e):\n        tool_spec['type'] = 'file_search'\n        tool = _build_tool(tool_spec, kernel)","preventionTips":["Always include type on every tool entry.","Validate tool specs before adding to spec.tools.","Drop malformed entries early."],"tags":["configuration","agents","openai-responses","tools","validation"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}