{"record":{"id":"2e27add8f2ad9389","repo":"FoundationAgents/MetaGPT","slug":"no-such-attribute-key","errorCode":null,"errorMessage":"No such attribute: {key}","messagePattern":"No such attribute: (.+?)","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"warning","filePath":"metagpt/context.py","lineNumber":45,"sourceCode":"    \"\"\"A dict-like object that allows access to keys as attributes, compatible with Pydantic.\"\"\"\n\n    model_config = ConfigDict(extra=\"allow\")\n\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n        self.__dict__.update(kwargs)\n\n    def __getattr__(self, key):\n        return self.__dict__.get(key, None)\n\n    def __setattr__(self, key, value):\n        self.__dict__[key] = value\n\n    def __delattr__(self, key):\n        if key in self.__dict__:\n            del self.__dict__[key]\n        else:\n            raise AttributeError(f\"No such attribute: {key}\")\n\n    def set(self, key, val: Any):\n        self.__dict__[key] = val\n\n    def get(self, key, default: Any = None):\n        return self.__dict__.get(key, default)\n\n    def remove(self, key):\n        if key in self.__dict__:\n            self.__delattr__(key)\n\n\nclass Context(BaseModel):\n    \"\"\"Env context for MetaGPT\"\"\"\n\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n\n    kwargs: AttrDict = AttrDict()","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/context.py#L27-L63","documentation":"metagpt Context uses plain __dict__ storage with permissive __getattr__ (unknown reads return None) but a strict __delattr__: deleting a key not present in self.__dict__ raises AttributeError 'No such attribute: {key}'. This asymmetry means reads never fail while deletes do, catching typos at cleanup time.","triggerScenarios":"Calling del context.some_key, context.__delattr__('x'), or context.remove('x') (remove delegates to __delattr__) for a key that was never set or was already deleted.","commonSituations":"Cleanup code that deletes optional keys unconditionally; double-delete in retry loops; typo'd key names; assuming getattr-returns-None semantics imply delete is also lenient.","solutions":["Use Context.remove(key) instead of del — it checks membership first and silently does nothing when absent.","Guard deletes: if key in ctx.__dict__: del ctx.__dict__[key].","Fix the key name typo revealed by the message."],"exampleFix":"# before\ndel ctx.options['reuseable']   # wrong/absent key -> AttributeError\n\n# after\nctx.remove('reusable')           # no-op if missing","handlingStrategy":"type-guard","validationCode":"if key in ctx.__dict__:\n    del ctx.__dict__[key]\n# or simply: ctx.remove(key)  which is already membership-guarded","typeGuard":"def has_context_key(ctx: Context, key: str) -> bool:\n    return key in ctx.__dict__","tryCatchPattern":null,"preventionTips":["Prefer Context.remove() over del for optional keys.","Remember __getattr__ returning None does not imply the key exists.","Avoid unconditional deletes in cleanup loops."],"tags":["context","attribute-error","cleanup","api-misuse"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}