{"id":"02306dcd6d59d40d","repo":"python-poetry/poetry","slug":"key-join-keys-not-in-config","errorCode":null,"errorMessage":"Key {'.'.join(keys)} not in config","messagePattern":"Key (.+?) not in config","errorType":"validation","errorClass":"PropertyNotFoundError","httpStatus":null,"severity":"error","filePath":"src/poetry/config/dict_config_source.py","lineNumber":29,"sourceCode":"if TYPE_CHECKING:\n    from collections.abc import Sequence\n\n\nclass DictConfigSource(ConfigSource):\n    def __init__(self) -> None:\n        self._config: dict[str, Any] = {}\n\n    @property\n    def config(self) -> dict[str, Any]:\n        return self._config\n\n    def get_property(self, key: str | Sequence[str]) -> Any:\n        keys = split_key(key)\n        config = self._config\n\n        for i, sub_key in enumerate(keys):\n            if sub_key not in config:\n                raise PropertyNotFoundError(f\"Key {'.'.join(keys)} not in config\")\n\n            if i == len(keys) - 1:\n                return config[sub_key]\n\n            config = config[sub_key]\n\n    def add_property(self, key: str | Sequence[str], value: Any) -> None:\n        keys = split_key(key)\n        config = self._config\n\n        for i, sub_key in enumerate(keys):\n            if sub_key not in config and i < len(keys) - 1:\n                config[sub_key] = {}\n\n            if i == len(keys) - 1:\n                config[sub_key] = value\n                break\n","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/config/dict_config_source.py#L11-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the dotted key spelling against the actual config structure; print self._config to inspect available top-level keys.","Wrap the get_property call in a try/except PropertyNotFoundError and supply a default value when the key is absent.","If probing for optional keys (as migrations do), catch PropertyNotFoundError explicitly and treat it as 'key not set' rather than an error."],"exampleFix":"// before\nvalue = source.get_property(\"repositories.foo.url\")\n// after\nfrom poetry.config.config_source import PropertyNotFoundError\ntry:\n    value = source.get_property(\"repositories.foo.url\")\nexcept PropertyNotFoundError:\n    value = None","handlingStrategy":"try-catch","validationCode":"from poetry.config.config_source import PropertyNotFoundError\n\ndef safe_get(source, key, default=None):\n    try:\n        return source.get_property(key)\n    except PropertyNotFoundError:\n        return default","typeGuard":"def key_exists(source, key) -> bool:\n    from poetry.config.config_source import PropertyNotFoundError\n    try:\n        source.get_property(key)\n        return True\n    except PropertyNotFoundError:\n        return False","tryCatchPattern":"from poetry.config.config_source import PropertyNotFoundError\n\ntry:\n    value = dict_source.get_property(\"some.dotted.key\")\nexcept PropertyNotFoundError as e:\n    # Key path does not exist in the in-memory config dict\n    value = None","preventionTips":["Always catch PropertyNotFoundError when probing for optional config keys.","Validate the top-level segment of the key exists in source.config before descending into nested lookups.","Prefer Config.get() over direct ConfigSource.get_property() for reads that should tolerate missing keys (Config.get returns None)."],"tags":["config","dict-config-source","property-not-found","valueerror"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}