microsoft/semantic-kernel · error · AgentInitializationException

Unresolved placeholders in spec: {', '.join(f'${{{key}}}' fo

Error message

Unresolved placeholders in spec: {', '.join(f'${{{key}}}' for key in unresolved)}

What it means

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.

Source

Thrown at python/semantic_kernel/agents/open_ai/openai_assistant_agent.py:594

        if extras:
            field_mapping.update(extras)

        def replacer(match: re.Match[str]) -> str:
            """Replace the matched placeholder with the corresponding value from field_mapping."""
            full_key = match.group(1)  # for example, OpenAI:ApiKey
            section, _, key = full_key.partition(":")
            if section != "OpenAI":
                return match.group(0)

            # Try short key first (ApiKey), then full (OpenAI:ApiKey)
            return str(field_mapping.get(key) or field_mapping.get(full_key) or match.group(0))

        result = pattern.sub(replacer, yaml_str)

        # Safety check for unresolved placeholders
        unresolved = pattern.findall(result)
        if unresolved:
            raise AgentInitializationException(
                f"Unresolved placeholders in spec: {', '.join(f'${{{key}}}' for key in unresolved)}"
            )

        return result

    # endregion

    # region Tool Handling

    @staticmethod
    def configure_code_interpreter_tool(
        file_ids: str | list[str] | None = None, **kwargs: Any
    ) -> tuple[list["AssistantToolParam"], ToolResources]:
        """Generate tool + tool_resources for the code_interpreter."""
        if isinstance(file_ids, str):
            file_ids = [file_ids]
        tool: "CodeInterpreterToolParam" = {"type": "code_interpreter"}
        resources: ToolResources = {}

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Provide the missing value via extras={'SomeField': value} or set the corresponding env var so the field_mapping entry is non-empty.
  2. Correct placeholder key names to match ChatModelId/AgentId/ApiKey exactly.
  3. Remove placeholders the resolver cannot fill, or pre-substitute non-OpenAI sections yourself before calling resolve_placeholders.

Example fix

# before
resolve_placeholders(yaml_str, settings=openai_settings)
# yaml has ${OpenAI:ProjectId}

# after
resolve_placeholders(yaml_str, settings=openai_settings, extras={'ProjectId': 'proj_123'})
Defensive patterns

Strategy: validation

Validate before calling

import re
placeholders = re.findall(r'\$\{([^}]+)\}', yaml_str)
known = {'ChatModelId','AgentId','ApiKey'} | set(extras or {})
unresolved = [p for p in placeholders if p.split(':')[-1] not in known]
assert not unresolved, f'unresolved: {unresolved}'

Type guard

null

Try / catch

from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException
try:
    out = resolve_placeholders(yaml_str, settings=s, extras=extras)
except AgentInitializationException as e:
    if 'Unresolved' in str(e):
        # parse missing keys from message, supply via extras, retry
        extras = extras or {}; extras.update(supply_missing())
        out = resolve_placeholders(yaml_str, settings=s, extras=extras)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/c72bd7b0d08cafc1. Report an issue: GitHub.