python-poetry/poetry · error · PropertyNotFoundError

Key {'.'.join(keys)} not in config

Error message

Key {'.'.join(keys)} not in config

What it means

Raised as PropertyNotFoundError (a ValueError subclass) by DictConfigSource.get_property() when a dotted config key path cannot be resolved against the in-memory dict. DictConfigSource is the pure-dictionary backend for config values; it walks each segment of the key in order and throws the moment a segment is absent. The message echoes the full dotted key so the caller knows exactly which path failed.

Source

Thrown at src/poetry/config/dict_config_source.py:29

if TYPE_CHECKING:
    from collections.abc import Sequence


class DictConfigSource(ConfigSource):
    def __init__(self) -> None:
        self._config: dict[str, Any] = {}

    @property
    def config(self) -> dict[str, Any]:
        return self._config

    def get_property(self, key: str | Sequence[str]) -> Any:
        keys = split_key(key)
        config = self._config

        for i, sub_key in enumerate(keys):
            if sub_key not in config:
                raise PropertyNotFoundError(f"Key {'.'.join(keys)} not in config")

            if i == len(keys) - 1:
                return config[sub_key]

            config = config[sub_key]

    def add_property(self, key: str | Sequence[str], value: Any) -> None:
        keys = split_key(key)
        config = self._config

        for i, sub_key in enumerate(keys):
            if sub_key not in config and i < len(keys) - 1:
                config[sub_key] = {}

            if i == len(keys) - 1:
                config[sub_key] = value
                break

View on GitHub (pinned to 92b74dcfe3)

Solutions

  1. Verify the dotted key spelling against the actual config structure; print self._config to inspect available top-level keys.
  2. Wrap the get_property call in a try/except PropertyNotFoundError and supply a default value when the key is absent.
  3. If probing for optional keys (as migrations do), catch PropertyNotFoundError explicitly and treat it as 'key not set' rather than an error.

Example fix

// before
value = source.get_property("repositories.foo.url")
// after
from poetry.config.config_source import PropertyNotFoundError
try:
    value = source.get_property("repositories.foo.url")
except PropertyNotFoundError:
    value = None
Defensive patterns

Strategy: try-catch

Validate before calling

from poetry.config.config_source import PropertyNotFoundError

def safe_get(source, key, default=None):
    try:
        return source.get_property(key)
    except PropertyNotFoundError:
        return default

Type guard

def key_exists(source, key) -> bool:
    from poetry.config.config_source import PropertyNotFoundError
    try:
        source.get_property(key)
        return True
    except PropertyNotFoundError:
        return False

Try / catch

from poetry.config.config_source import PropertyNotFoundError

try:
    value = dict_source.get_property("some.dotted.key")
except PropertyNotFoundError as e:
    # Key path does not exist in the in-memory config dict
    value = None

Prevention

When it happens

Trigger: Calling DictConfigSource.get_property(key) where any segment of key (split on '.') is not present in self._config. For example get_property('repositories.foo.url') when _config has no 'repositories' key, or when an intermediate table is missing.

Common situations: Querying a config setting that was never set, reading a nested key after a migration removed its parent table, or a typo in the dotted key string. Also occurs internally during config migrations (ConfigSourceMigration.dry_run) when probing for old keys that may not exist.

Related errors


AI-assisted analysis of python-poetry/poetry@92b74dcfe3 (2026-08-04). Data as JSON: /data/errors/02306dcd6d59d40d.json. Report an issue: GitHub.