{"record":{"id":"6925535cf2e50a74","repo":"NationalSecurityAgency/ghidra","slug":"given-bookmark-is-not-present-at-this-view-s-snap","errorCode":null,"errorMessage":"Given bookmark is not present at this view's snap","messagePattern":"Given bookmark is not present at this view's snap","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java","lineNumber":115,"sourceCode":"\t\t\tfor (long s : program.viewport.getOrderedSnaps()) {\n\t\t\t\tfor (TraceBookmark bm : space.getBookmarksAt(s, addr)) {\n\t\t\t\t\tif (!type.equals(bm.getTypeString())) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (!category.equals(bm.getCategory())) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\treturn bm;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected void doDeleteOrTruncateLifespan(TraceBookmark bm) {\n\t\tLifespan lifespan = bm.getLifespan();\n\t\tif (!lifespan.contains(program.snap)) {\n\t\t\tthrow new IllegalArgumentException(\"Given bookmark is not present at this view's snap\");\n\t\t}\n\t\tif (lifespan.lmin() == program.snap) {\n\t\t\tbm.delete();\n\t\t}\n\t\telse {\n\t\t\tbm.setLifespan(lifespan.intersect(Lifespan.before(program.snap)));\n\t\t}\n\t}\n\n\t@Override\n\tpublic void removeBookmark(Bookmark bookmark) {\n\t\tif (!(bookmark instanceof DBTraceBookmark)) {\n\t\t\tthrow new IllegalArgumentException(\"Given bookmark is not part of this trace\");\n\t\t}\n\t\tDBTraceBookmark dbBookmark = (DBTraceBookmark) bookmark;\n\t\tif (dbBookmark.getTrace() != program.trace) {\n\t\t\tthrow new IllegalArgumentException(\"Given bookmark is not part of this trace\");\n\t\t}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java#L97-L133","documentation":"Thrown as IllegalArgumentException by doDeleteOrTruncateLifespan when the bookmark's lifespan does not contain the current view snap. A trace bookmark lives for a Lifespan of snaps; the program view operates at a single snap. You can only delete or truncate a bookmark that is actually present (alive) at the snap the view is displaying.","triggerScenarios":"Calling removeBookmark (or any path into doDeleteOrTruncateLifespan) for a bookmark whose Lifespan does not enclose program.snap — e.g. the bookmark was created at a later snap or already truncated before the current snap.","commonSituations":"Removing a bookmark obtained from a different snap than the view's current snap. Operating on a bookmark that expired at an earlier snap. Switching the view's snap after fetching bookmarks and then trying to delete one not alive at the new snap.","solutions":["Verify bm.getLifespan().contains(programView.getSnap()) before attempting to remove or truncate.","Fetch bookmarks at the view's current snap so they are guaranteed present.","Re-fetch or recreate the bookmark at the desired snap before deleting."],"exampleFix":"// before\nbookmarkManager.removeBookmark(bm);\n\n// after\nif (bm.getLifespan().contains(programView.getSnap())) {\n    bookmarkManager.removeBookmark(bm);\n}","handlingStrategy":"validation","validationCode":"// Verify the bookmark is alive at the view's snap before removing\nlong snap = programView.getSnap();\nif (bm.getLifespan().contains(snap)) {\n    bookmarkManager.removeBookmark(bm);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check lifespan.contains(viewSnap) before removing a bookmark.","Fetch bookmarks at the view's current snap.","Do not cache bookmark handles across snap switches."],"tags":["trace-modeling","bookmark","lifespan","snapshot","validation","ghidra"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}