{"record":{"id":"c701bfa3ca79d61d","repo":"stamparm/maltrail","slug":"cannot-iterate-a-finalized-trailsdict-keys-are-not-retained","errorCode":null,"errorMessage":"cannot iterate a finalized TrailsDict (keys are not retained)","messagePattern":"cannot iterate a finalized TrailsDict \\(keys are not retained\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/trailsdict.py","lineNumber":297,"sourceCode":"        self._trails[key] = shared\n\n    def __delitem__(self, key):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot modify a finalized TrailsDict\")\n        del self._trails[key]\n\n    def update(self, value):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot modify a finalized TrailsDict\")\n        if isinstance(value, (TrailsDict, dict)):\n            for key in value:\n                self[key] = value[key]\n        else:\n            raise Exception(\"unsupported type '%s'\" % type(value))\n\n    def keys(self):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot iterate a finalized TrailsDict (keys are not retained)\")\n        return self._trails.keys()\n\n    def iterkeys(self):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot iterate a finalized TrailsDict (keys are not retained)\")\n        for key in self._trails:\n            yield key\n\n    # NOTE: items()/values() are NOT inherited from dict here - the dict base is always empty (all data lives in\n    # self._trails), so the inherited versions would silently return nothing. Route them to _trails, matching keys().\n    def items(self):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot iterate a finalized TrailsDict (keys are not retained)\")\n        return self._trails.items()\n\n    def values(self):\n        if self._frozen is not None or self._mmap is not None:\n            raise Exception(\"cannot iterate a finalized TrailsDict (keys are not retained)\")","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/core/trailsdict.py#L279-L315","documentation":"After finalize(), key strings are deliberately discarded to save ~90MB per 1.6M trails; only 64-bit hashes packed into an array remain. keys() therefore cannot return the original keys and raises this exception on a finalized (or mmap-backed) instance rather than returning a wrong/partial result. Lookups, membership tests, get(), and len() still work.","triggerScenarios":"Calling trails.keys(), list(trails), dict(trails), or any iteration over keys after finalize() or open_mmap(). Note keys() itself checks eagerly, so even an unchecked .keys() (no list()) throws.","commonSituations":"Debug/logging code that dumps trail names after the sensor finalized; code computing set differences (set(trails) - known) post-finalize; pickling/copying via dict(trails); doctests or unit tests that enumerate keys on a finalized store.","solutions":["Keep the pre-finalization build-mode dict (or a serialized key list) if you need key enumeration; finalize a separate copy used only for lookups.","Use membership tests (\"trail\" in trails) and get() instead of iterating keys where possible.","Persist keys before finalize() (e.g. write the build-mode keys to a file) and read them back when enumeration is needed.","Refactor to pass the build-mode TrailsDict to the consumer; only the sensor hot path needs the finalized one."],"exampleFix":"// before\ntrails.finalize()\nfor key in trails.keys():  # Exception\n    log(key)\n// after\nkeys_snapshot = list(trails.keys())  # before finalize\ntrails.finalize()\nfor key in keys_snapshot:\n    log(key)","handlingStrategy":"validation","validationCode":"if trails._frozen is not None or trails._mmap is not None:\n    raise RuntimeError(\"keys are not retained after finalize(); snapshot keys before finalizing\")","typeGuard":"def can_iterate_keys(t):\n    return isinstance(t, TrailsDict) and t._frozen is None and t._mmap is None","tryCatchPattern":"try:\n    keys = list(trails.keys())\nexcept Exception:\n    keys = load_persisted_key_snapshot()  # saved before finalize()","preventionTips":["Snapshot list(trails.keys()) before calling finalize().","On finalized dicts use only membership tests, get(), and len().","Persist the build-mode key list to disk if post-finalize enumeration is foreseeable.","Keep the enum-needed consumer pointed at a build-mode copy."],"tags":["python","readonly-state","iteration","immutable-after-finalize"],"backgroundTag":"unsupported-operation","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}