{"record":{"id":"6df16277e7177ae4","repo":"a-b-street/abstreet","slug":"can-t-delete-it-s-not-in-the-world","errorCode":null,"errorMessage":"Can't delete {:?}; it's not in the World","messagePattern":"Can't delete (.+?); it's not in the World","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widgetry/src/mapspace/world.rs","lineNumber":412,"sourceCode":"            if self.dragging_from.is_some() {\n                panic!(\"Can't delete {:?} mid-drag\", id);\n            }\n        }\n\n        self.delete_before_replacement(id);\n    }\n\n    /// Delete an object, with the promise to recreate it with the same ID before the next call to\n    /// `event`. This may be called while the object is being hovered on or dragged.\n    pub fn delete_before_replacement(&mut self, id: ID) {\n        if self.objects.remove(&id).is_some() {\n            if self.quadtree.remove(id).is_none() {\n                // This can happen for objects that're out-of-bounds. One example is intersections\n                // in map_editor.\n                warn!(\"{:?} wasn't in the quadtree\", id);\n            }\n        } else {\n            panic!(\"Can't delete {:?}; it's not in the World\", id);\n        }\n    }\n\n    /// Like delete, but doesn't crash if the object doesn't exist\n    pub fn maybe_delete(&mut self, id: ID) {\n        if self.hovering == Some(id) {\n            self.hovering = None;\n            self.draw_hovering = None;\n            if self.dragging_from.is_some() {\n                panic!(\"Can't delete {:?} mid-drag\", id);\n            }\n        }\n\n        if self.objects.remove(&id).is_some() {\n            if self.quadtree.remove(id).is_none() {\n                // This can happen for objects that're out-of-bounds. One example is intersections\n                // in map_editor.\n                warn!(\"{:?} wasn't in the quadtree\", id);","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/mapspace/world.rs#L394-L430","documentation":"World::delete panics when the given ID is not present in the World's object map. The library tracks drawable objects by ID; deleting something already removed or never added is a caller bug, so it panics rather than silently no-op. Use maybe_delete when a missing object is expected.","triggerScenarios":"Calling world.delete(id) twice for the same ID, deleting an ID created by another World instance, or deleting after the object was already consumed/removed elsewhere.","commonSituations":"Double-handling a UI callback (click handler fires delete twice), stale IDs captured from a previous draw cycle, objects removed by map_editor logic before a subsequent delete call.","solutions":["Switch to world.maybe_delete(id) if absence is a legitimate case.","Guard with a check that the ID is still tracked before deleting.","Deduplicate the call path so delete is invoked once per object lifecycle."],"exampleFix":"// before\nworld.delete(id);\n// after\nworld.maybe_delete(id);","handlingStrategy":"fallback","validationCode":"// Only delete IDs you currently own/track\nif tracked_ids.contains(&id) { world.delete(id); }","typeGuard":null,"tryCatchPattern":"world.maybe_delete(id); // tolerant variant instead of delete","preventionTips":["Prefer maybe_delete whenever object lifetime is uncertain","Clear stale IDs after each rebuild of the World","Avoid deleting the same ID from multiple event handlers"],"tags":["rust","panic","state","widgetry"],"backgroundTag":"entity-not-found","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}