{"record":{"id":"5e772720f877641b","repo":"pulumi/pulumi","slug":"can-t-set-key-values-on-non-dict-variables","errorCode":null,"errorMessage":"Can't set key values on non-dict variables.","messagePattern":"Can't set key values on non-dict variables\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdk/python/lib/pulumi/_utils.py","lineNumber":228,"sourceCode":"\n    def fdel(self, *_):\n        return self._data.reset()\n\n    def __set__(self, _, v: typing.Any):\n        return self.fset(v)\n\n    def __get__(self, obj: typing.Optional[typing.Any], _):\n        if obj is None or isinstance(self.fget(), dict):\n            return self\n        return self.fget()\n\n    def __delete__(self, *_):\n        self.fdel()\n\n    def __setitem__(self, key, value):\n        data = self.fget()\n        if not isinstance(data, dict):\n            raise TypeError(\"Can't set key values on non-dict variables.\")\n        data[key] = value\n        return self.fset(data)\n\n    def __dict__(self):\n        if not isinstance(self.fget(), dict):\n            raise TypeError(f\"{self} is not a dictionary\")\n        return self.fget()\n\n    def __getitem__(self, key):\n        return self.fget()[key]\n\n    def get(self, key, default=None):\n        data = self.fget()\n        if not isinstance(data, dict):\n            raise TypeError(\"Can't get key values on non-dict variables.\")\n        return data.get(key, default)\n\n    def __contains__(self, element):","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/python/lib/pulumi/_utils.py#L210-L246","documentation":"Pulumi's `_utils.py` provides a descriptor-based lazy property wrapper whose `__setitem__` delegates to the wrapped getter, mutates the returned mapping, and writes it back via the setter. If the getter returns anything that is not a `dict`, key assignment is impossible and this TypeError is raised. It protects against silently overwriting non-dict values.","triggerScenarios":"Executing `obj.prop[key] = value` where `obj.prop` is the wrapped property and its getter returns a list, string, None, or custom object instead of a dict.","commonSituations":"A config/opts getter that was changed to return a list or Optional[dict]; the underlying attribute still None before initialization; a refactored getter returning a dataclass or named tuple.","solutions":["Make the underlying getter return a dict (initialize it to `{}` instead of None).","Assign the whole value instead of item assignment: `obj.prop = {'key': value}`.","If the value is genuinely a list, build the list separately and assign it via the setter.","Guard with isinstance before item assignment."],"exampleFix":"// before\nobj.tags[\"env\"] = \"prod\"  # getter returns None\n\n// after\nif isinstance(obj.tags, dict):\n    obj.tags[\"env\"] = \"prod\"\nelse:\n    obj.tags = {\"env\": \"prod\"}","handlingStrategy":"type-guard","validationCode":"value = obj.prop\nif not isinstance(value, dict):\n    obj.prop = {}\nobj.prop[key] = new_value","typeGuard":"def is_dict_value(v) -> TypeGuard[dict]:\n    return isinstance(v, dict)","tryCatchPattern":"try:\n    obj.prop[key] = value\nexcept TypeError as e:\n    if \"non-dict\" in str(e):\n        obj.prop = {key: value}\n    else:\n        raise","preventionTips":["Initialize wrapped properties to {} not None.","Keep getters returning dict only.","Assign whole dicts instead of item assignment when type is uncertain."],"tags":["python","utils","descriptor","dict","type-error"],"backgroundTag":"non-dict-property","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}