{"record":{"id":"c72bd7b0d08cafc1","repo":"microsoft/semantic-kernel","slug":"unresolved-placeholders-in-spec-join-f-c72bd7","errorCode":null,"errorMessage":"Unresolved placeholders in spec: {', '.join(f'${{{key}}}' for key in unresolved)}","messagePattern":"Unresolved placeholders in spec: (.+?)\\}' for key in unresolved\\)\\}","errorType":"exception","errorClass":"AgentInitializationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/agents/open_ai/openai_assistant_agent.py","lineNumber":594,"sourceCode":"        if extras:\n            field_mapping.update(extras)\n\n        def replacer(match: re.Match[str]) -> str:\n            \"\"\"Replace the matched placeholder with the corresponding value from field_mapping.\"\"\"\n            full_key = match.group(1)  # for example, OpenAI:ApiKey\n            section, _, key = full_key.partition(\":\")\n            if section != \"OpenAI\":\n                return match.group(0)\n\n            # Try short key first (ApiKey), then full (OpenAI:ApiKey)\n            return str(field_mapping.get(key) or field_mapping.get(full_key) or match.group(0))\n\n        result = pattern.sub(replacer, yaml_str)\n\n        # Safety check for unresolved placeholders\n        unresolved = pattern.findall(result)\n        if unresolved:\n            raise AgentInitializationException(\n                f\"Unresolved placeholders in spec: {', '.join(f'${{{key}}}' for key in unresolved)}\"\n            )\n\n        return result\n\n    # endregion\n\n    # region Tool Handling\n\n    @staticmethod\n    def configure_code_interpreter_tool(\n        file_ids: str | list[str] | None = None, **kwargs: Any\n    ) -> tuple[list[\"AssistantToolParam\"], ToolResources]:\n        \"\"\"Generate tool + tool_resources for the code_interpreter.\"\"\"\n        if isinstance(file_ids, str):\n            file_ids = [file_ids]\n        tool: \"CodeInterpreterToolParam\" = {\"type\": \"code_interpreter\"}\n        resources: ToolResources = {}","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/open_ai/openai_assistant_agent.py#L576-L612","documentation":"Raised by resolve_placeholders() after running regex substitution when one or more ${...} placeholders remain in the YAML string. The replacer only substitutes keys under the OpenAI: section that exist in field_mapping (ChatModelId, AgentId, ApiKey) or in extras; any placeholder whose key is unknown is left intact and then flagged here so the spec is never silently shipped with template holes.","triggerScenarios":"A spec contains ${OpenAI:SomeField} where SomeField is not chat_model_id/agent_id/api_key and not in extras; a non-OpenAI placeholder like ${Other:Key} that the replacer deliberately leaves untouched (section != OpenAI); typos in placeholder names; missing env values so field_mapping entries are None and the 'or' chain falls through to the original match.","commonSituations":"Templated YAML with placeholders for values not provided via env/extras; placeholder naming mismatch (ApiKey vs APIKey); settings loaded but a field is None so the value resolves falsy; referencing a section the resolver does not handle.","solutions":["Provide the missing value via extras={'SomeField': value} or set the corresponding env var so the field_mapping entry is non-empty.","Correct placeholder key names to match ChatModelId/AgentId/ApiKey exactly.","Remove placeholders the resolver cannot fill, or pre-substitute non-OpenAI sections yourself before calling resolve_placeholders."],"exampleFix":"# before\nresolve_placeholders(yaml_str, settings=openai_settings)\n# yaml has ${OpenAI:ProjectId}\n\n# after\nresolve_placeholders(yaml_str, settings=openai_settings, extras={'ProjectId': 'proj_123'})","handlingStrategy":"validation","validationCode":"import re\nplaceholders = re.findall(r'\\$\\{([^}]+)\\}', yaml_str)\nknown = {'ChatModelId','AgentId','ApiKey'} | set(extras or {})\nunresolved = [p for p in placeholders if p.split(':')[-1] not in known]\nassert not unresolved, f'unresolved: {unresolved}'","typeGuard":"null","tryCatchPattern":"from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException\ntry:\n    out = resolve_placeholders(yaml_str, settings=s, extras=extras)\nexcept AgentInitializationException as e:\n    if 'Unresolved' in str(e):\n        # parse missing keys from message, supply via extras, retry\n        extras = extras or {}; extras.update(supply_missing())\n        out = resolve_placeholders(yaml_str, settings=s, extras=extras)","preventionTips":["Match placeholder keys to ChatModelId/AgentId/ApiKey exactly.","Provide all non-OpenAI values via extras.","Strip placeholders you cannot fill."],"tags":["configuration","agents","openai-assistant","declarative-spec","templating"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}