{"record":{"id":"c8fb881f8924c3c0","repo":"dbeaver/dbeaver","slug":"data-source-id-missing-in-bookmark-definition","errorCode":null,"errorMessage":"Data source ID missing in bookmark definition","messagePattern":"Data source ID missing in bookmark definition","errorType":"exception","errorClass":"DBException","httpStatus":null,"severity":"warning","filePath":"plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/bookmarks/BookmarkStorage.java","lineNumber":71,"sourceCode":"    public static final String TAG_PATH = \"path\"; //NON-NLS-1\r\n    public static final String TAG_IMAGE = \"image\"; //NON-NLS-1\r\n    public static final String TAG_BOOKMARK = \"bookmark\"; //NON-NLS-1\r\n    private String title;\r\n    private String description;\r\n    private DBPImage image;\r\n    private String dataSourceId;\r\n    private List<String> dataSourcePath;\r\n\r\n    public BookmarkStorage(IFile file, boolean loadImage) throws DBException, CoreException {\r\n        this.title = file.getFullPath().removeFileExtension().lastSegment();\r\n        try (InputStream contents = file.getContents(true)) {\r\n            final Document document = XMLUtils.parseDocument(contents);\r\n            final Element root = document.getDocumentElement();\r\n            this.title = root.getAttribute(ATTR_TITLE);\r\n            this.description = root.getAttribute(ATTR_DESCRIPTION);\r\n            this.dataSourceId = root.getAttribute(ATTR_DATA_SOURCE);\r\n            if (dataSourceId == null) {\r\n                throw new DBException(\"Data source ID missing in bookmark definition\");\r\n            }\r\n            this.dataSourcePath = new ArrayList<>();\r\n            for (Element elem : XMLUtils.getChildElementList(root, TAG_PATH)) {\r\n                this.dataSourcePath.add(XMLUtils.getElementBody(elem));\r\n            }\r\n            if (loadImage) {\r\n                Element imgElement = XMLUtils.getChildElement(root, TAG_IMAGE);\r\n                if (imgElement != null) {\r\n                    String imgString = XMLUtils.getElementBody(imgElement);\r\n                    final byte[] imgBytes = Base64.decode(imgString);\r\n                    ImageLoader loader = new ImageLoader();\r\n                    this.image = new DBIconBinary(\r\n                        dataSourcePath.toString(),\r\n                        loader.load(new ByteArrayInputStream(imgBytes))[0]);\r\n                }\r\n            }\r\n        } catch (XMLException e) {\r\n            throw new DBException(\"Error reading bookmarks storage\", e);\r","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/dbeaver/dbeaver/blob/1e5ee1042bc61661368942aece126f3e67049955/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/bookmarks/BookmarkStorage.java#L53-L89","documentation":"Thrown by BookmarkStorage constructor when parsing a bookmark XML file and the 'data-source' attribute (ATTR_DATA_SOURCE) is null on the root element. NOTE: org.w3c.dom.Element.getAttribute() never returns null — it returns an empty string for absent attributes. This means the null check on line 70 will not fire for a genuinely missing attribute; it would only fire if the attribute value were explicitly set to null via DOM manipulation, making this a latent bug.","triggerScenarios":"root.getAttribute(ATTR_DATA_SOURCE) is checked against null. In practice, a missing data-source attribute yields \"\" (empty string), not null, so this specific throw is effectively unreachable through normal XML parsing. A bookmark file missing the data-source attribute would silently pass this check with an empty dataSourceId.","commonSituations":"A bookmark XML file that was hand-edited or produced by a buggy export and is missing the data-source attribute. However, due to the DOM API contract, the null check would not catch this — the bookmark would load with an empty dataSourceId and fail later. This error is theoretically for missing data-source references but the guard is incorrect.","solutions":["Ensure bookmark XML files include the data-source attribute: <bookmark data-source=\"connection-id\" ...>","If maintaining this code, fix the check to also test for empty string: if (dataSourceId == null || dataSourceId.isEmpty())","Regenerate the bookmark from the DBeaver UI to ensure all required attributes are present"],"exampleFix":"// before\nif (dataSourceId == null) {\n    throw new DBException(\"Data source ID missing in bookmark definition\");\n}\n\n// after\nif (CommonUtils.isEmpty(dataSourceId)) {\n    throw new DBException(\"Data source ID missing in bookmark definition\");\n}","handlingStrategy":"validation","validationCode":"String dsId = root.getAttribute(ATTR_DATA_SOURCE);\n// NOTE: getAttribute returns \"\" not null for missing attributes — check both\nif (dsId == null || dsId.trim().isEmpty()) {\n    throw new DBException(\"Data source ID missing in bookmark definition\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure bookmark XML files always include the data-source attribute","Fix the null check to also handle empty strings (CommonUtils.isEmpty)","Regenerate bookmarks from the DBeaver UI rather than editing XML by hand"],"tags":["bookmarks","xml","validation","latent-bug","dom"],"backgroundTag":null,"analyzedSha":"1e5ee1042bc61661368942aece126f3e67049955","analyzedAt":"2026-08-13T23:31:13.467Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}