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

Source

Thrown at python/semantic_kernel/agents/open_ai/openai_responses_agent.py:631

        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_file_search_tool(
        vector_store_ids: str | list[str],
        filters: ComparisonFilter | CompoundFilter | None = None,
        max_num_results: int | None = None,
        score_threshold: float | None = None,
        ranker: Literal["auto", "default-2024-11-15"] | None = None,
    ) -> FileSearchToolParam:
        """Generate the file search tool param.

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Read the unresolved keys in the message; for each, either fix the placeholder name or supply the value via the extras dict.
  2. Ensure the referenced OpenAISettings field actually exists (responses_model_id, agent_id, api_key are mapped).
  3. Remove the placeholder from the spec if the value is not needed.
  4. Provide extras={"Region": "eastus"} to satisfy custom placeholders.

Example fix

// before
# yaml contains: model: ${OpenAI:Region}
result = OpenAIResponsesAgent._substitute_placeholders(yaml)

// after
result = OpenAIResponsesAgent._substitute_placeholders(yaml, extras={"Region": "eastus"})
Defensive patterns

Strategy: validation

Validate before calling

import re
placeholders = set(re.findall(r'\$\{([^}]+)\}', yaml_str))
known = {'OpenAI:ChatModelId', 'OpenAI:AgentId', 'OpenAI:ApiKey'}
unresolved = placeholders - known - {f'OpenAI:{k}' for k in extras}
if unresolved:
    raise ValueError(f'Add extras for: {unresolved}')

Type guard

import re
def spec_has_unresolved_placeholders(yaml_str: str, extras: dict) -> list:
    tokens = set(re.findall(r'\$\{([^}]+)\}', yaml_str))
    resolvable = {'OpenAI:ChatModelId', 'OpenAI:AgentId', 'OpenAI:ApiKey'} | {f'OpenAI:{k}' for k in extras}
    return [t for t in tokens if t not in resolvable]

Try / catch

from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException
try:
    result = OpenAIResponsesAgent._substitute_placeholders(yaml, extras=extras)
except AgentInitializationException as e:
    if 'Unresolved' in str(e):
        extras.update({k: '' for k in re.findall(r'\$\{OpenAI:([^}]+)\}', str(e))})
    raise

Prevention

When it happens

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

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

Related errors


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