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
- 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.
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
- 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.
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
- Unresolved placeholders in spec: {', '.join(f'${{{key}}}' fo
- Missing or malformed 'tool_connections' in: {spec}
- Missing or malformed 'index_name' in: {spec}
- Missing or malformed 'vector_store_ids' in: {spec}
- Function ID is required for function tools.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/8c214b84a46a1e54.
Report an issue: GitHub.