{"record":{"id":"8c214b84a46a1e54","repo":"microsoft/semantic-kernel","slug":"unresolved-placeholders-in-spec-join-f-8c214b","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_responses_agent.py","lineNumber":631,"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_file_search_tool(\n        vector_store_ids: str | list[str],\n        filters: ComparisonFilter | CompoundFilter | None = None,\n        max_num_results: int | None = None,\n        score_threshold: float | None = None,\n        ranker: Literal[\"auto\", \"default-2024-11-15\"] | None = None,\n    ) -> FileSearchToolParam:\n        \"\"\"Generate the file search tool param.","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/open_ai/openai_responses_agent.py#L613-L649","documentation":"Raised by the placeholder-substitution helper when, after replacing all known ${...} tokens, the resulting string still contains placeholder patterns. This means a referenced field (e.g. ${OpenAI:Something}) had no matching entry in the field mapping built from OpenAISettings and extras, so the token was left literally in the YAML.","triggerScenarios":"A declarative spec YAML references a placeholder key that OpenAISettings does not expose (e.g. ${OpenAI:Region}) and it was not supplied via the extras dict. The replacer falls through to match.group(0) (the raw token), which the post-substitution safety scan then catches.","commonSituations":"Typo in a placeholder name, referencing an env var key that isn't part of OpenAISettings, or expecting a field (like a deployment name) that the Responses settings object doesn't carry. The error message lists every unresolved key.","solutions":["Read the unresolved keys in the message; for each, either fix the placeholder name or supply the value via the extras dict.","Ensure the referenced OpenAISettings field actually exists (responses_model_id, agent_id, api_key are mapped).","Remove the placeholder from the spec if the value is not needed.","Provide extras={\"Region\": \"eastus\"} to satisfy custom placeholders."],"exampleFix":"// before\n# yaml contains: model: ${OpenAI:Region}\nresult = OpenAIResponsesAgent._substitute_placeholders(yaml)\n\n// after\nresult = OpenAIResponsesAgent._substitute_placeholders(yaml, extras={\"Region\": \"eastus\"})","handlingStrategy":"validation","validationCode":"import re\nplaceholders = set(re.findall(r'\\$\\{([^}]+)\\}', yaml_str))\nknown = {'OpenAI:ChatModelId', 'OpenAI:AgentId', 'OpenAI:ApiKey'}\nunresolved = placeholders - known - {f'OpenAI:{k}' for k in extras}\nif unresolved:\n    raise ValueError(f'Add extras for: {unresolved}')","typeGuard":"import re\ndef spec_has_unresolved_placeholders(yaml_str: str, extras: dict) -> list:\n    tokens = set(re.findall(r'\\$\\{([^}]+)\\}', yaml_str))\n    resolvable = {'OpenAI:ChatModelId', 'OpenAI:AgentId', 'OpenAI:ApiKey'} | {f'OpenAI:{k}' for k in extras}\n    return [t for t in tokens if t not in resolvable]","tryCatchPattern":"from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException\ntry:\n    result = OpenAIResponsesAgent._substitute_placeholders(yaml, extras=extras)\nexcept AgentInitializationException as e:\n    if 'Unresolved' in str(e):\n        extras.update({k: '' for k in re.findall(r'\\$\\{OpenAI:([^}]+)\\}', str(e))})\n    raise","preventionTips":["Only reference placeholders backed by OpenAISettings fields or extras.","Supply extras for any custom (non-standard) placeholders in your spec.","Scan spec YAML for ${...} tokens during CI to catch typos early."],"tags":["declarative-spec","placeholders","configuration"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}