{"record":{"id":"15d670dee5a99c7c","repo":"matplotlib/matplotlib","slug":"spines-object-does-not-contain-a-name-spine","errorCode":null,"errorMessage":"'Spines' object does not contain a '{name}' spine","messagePattern":"'Spines' object does not contain a '(.+?)' spine","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/spines.py","lineNumber":590,"sourceCode":"    \"\"\"\n    def __init__(self, **kwargs):\n        self._dict = kwargs\n\n    @classmethod\n    def from_dict(cls, d):\n        return cls(**d)\n\n    def __getstate__(self):\n        return self._dict\n\n    def __setstate__(self, state):\n        self.__init__(**state)\n\n    def __getattr__(self, name):\n        try:\n            return self._dict[name]\n        except KeyError:\n            raise AttributeError(\n                f\"'Spines' object does not contain a '{name}' spine\")\n\n    def __getitem__(self, key):\n        if isinstance(key, list):\n            unknown_keys = [k for k in key if k not in self._dict]\n            if unknown_keys:\n                raise KeyError(', '.join(unknown_keys))\n            return SpinesProxy({k: v for k, v in self._dict.items()\n                                if k in key})\n        if isinstance(key, tuple):\n            raise ValueError('Multiple spines must be passed as a single list')\n        if isinstance(key, slice):\n            if key.start is None and key.stop is None and key.step is None:\n                return SpinesProxy(self._dict)\n            else:\n                raise ValueError(\n                    'Spines does not support slicing except for the fully '\n                    'open slice [:] to access all spines.')","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/spines.py#L572-L608","documentation":"Spines maps attribute access onto its internal dict: ax.spines.left returns the 'left' Spine. When the name is neither a real Spines attribute nor a key in the dict, __getattr__ raises this AttributeError. Typical causes: a typo ('leftt'), a name that does not exist on that Axes class ('polar' on a Cartesian Axes), or access after the spine was removed with del ax.spines['top'].","triggerScenarios":"ax.spines.leftt; getattr(ax.spines, name) for configured names that are absent on this Axes; ax.spines.top after `del ax.spines['top']`.","commonSituations":"Style code written for one Axes type reused on another (polar, 3D, geo); config-driven spine styling where names come from a file and are never checked.","solutions":["Check membership first: if 'top' in ax.spines: ax.spines['top'].set_visible(False)","Use the documented names: 'left', 'right', 'top', 'bottom' plus projection-specific ones ('polar', 'inner', 'geo')","Re-add a deleted spine with ax.spines['top'] = Spine.linear_spine(ax, 'top')"],"exampleFix":"# before\nax.spines.toop.set_visible(False)  # AttributeError: no 'toop' spine\n\n# after\nif 'top' in ax.spines:\n    ax.spines['top'].set_visible(False)","handlingStrategy":"type-guard","validationCode":"if 'top' in ax.spines:          # membership check before access\n    ax.spines['top'].set_visible(False)","typeGuard":"def has_spine(ax, name: str) -> bool:\n    return name in ax.spines  # hasattr(ax.spines, name) also works","tryCatchPattern":"try:\n    spine = ax.spines[name]\nexcept (AttributeError, KeyError):\n    spine = None  # spine absent on this Axes type; skip styling","preventionTips":["Check 'name' in ax.spines or hasattr(ax.spines, name) before attribute access","Remember projection Axes carry different spine names ('polar', 'inner', 'geo')","Style code reused across Axes types should iterate ax.spines.keys(), not hardcode names"],"tags":["matplotlib","spines","attributeerror","dict-access"],"backgroundTag":"missing-spine-key","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}