{"record":{"id":"ac9c5dcd22a30fe1","repo":"NationalSecurityAgency/ghidra","slug":"functiondescription-does-not-have-id","errorCode":null,"errorMessage":"FunctionDescription does not have id","messagePattern":"FunctionDescription does not have id","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/tables/CallgraphTable.java","lineNumber":90,"sourceCode":"\t}\n\n\t/**\n\t * \n\t * @param func the function description\n\t * @param trackcallgraph true if the database tracks call graph information\n\t * @return the list of {@link CallgraphRow}s\n\t * @throws SQLException if there is a problem parsing the {@link ResultSet} objects\n\t */\n\tpublic List<CallgraphRow> queryCallgraphRows(FunctionDescription func,\n\t\tboolean trackcallgraph) throws SQLException {\n\t\tif (!trackcallgraph) {\n\t\t\tthrow new SQLException(\"SQL database does not have callgraph information enabled\");\n\t\t}\n\t\tPreparedStatement s =\n\t\t\tselectStatement.prepareIfNeeded(() -> db.prepareStatement(SELECT_STMT));\n\t\tRowKey funcid = func.getId();\n\t\tif (funcid == null) {\n\t\t\tthrow new SQLException(\"FunctionDescription does not have id\");\n\t\t}\n\t\ts.setLong(1, funcid.getLong());\n\t\ttry (ResultSet rs = s.executeQuery()) {\n\t\t\tList<CallgraphRow> callvec = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tCallgraphRow row = extractCallgraphRow(rs);\n\t\t\t\tif (row.dest == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcallvec.add(row);\n\t\t\t}\n\t\t\treturn callvec;\n\t\t}\n\t}\n\n\t@Override\n\tpublic long insert(Object... arguments) throws SQLException {\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/tables/CallgraphTable.java#L72-L108","documentation":"Thrown by CallgraphTable.queryCallgraphRows when func.getId() returns null — the FunctionDescription object has not been assigned a database row id. The callgraph table is keyed by function id, so a null id makes the query impossible. This usually means the function was constructed in-memory and never inserted/queried from the database, or its id was never set after insertion.","triggerScenarios":"Passing a FunctionDescription to queryCallgraphRows that was created via DescriptionManager but never persisted (no row id assigned). Or a function object whose id field was not populated after an insert because the generated-keys step was skipped. Any callgraph query on an un-inserted function.","commonSituations":"Building FunctionDescription objects locally for matching without first resolving them against the database. Performing an insert but using the pre-insert object reference whose id is still null. Mixing in-memory and database-backed function objects and querying callgraph on the wrong kind.","solutions":["Ensure the FunctionDescription has been inserted into (or queried from) the database so its row id is set before calling callgraph queries.","Add a null check on func.getId() before invoking and throw a clearer upstream error or skip.","Resolve the function by name/exe via DescriptionTable.querySingleDescriptionId to obtain a db-backed object with an id.","Verify the insertion path returns and assigns the generated id (see error 807)."],"exampleFix":"// before\nList<CallgraphRow> rows = callgraphTable.queryCallgraphRows(func, true); // func.getId()==null\n\n// after\nRowKey id = func.getId();\nif (id == null) {\n    throw new IllegalStateException(\"Function must be persisted before callgraph query: \" + func.getFunctionName());\n}\nList<CallgraphRow> rows = callgraphTable.queryCallgraphRows(func, true);","handlingStrategy":"validation","validationCode":"// Ensure the FunctionDescription has a row id before callgraph queries.\nRowKey id = func.getId();\nif (id == null) {\n    throw new IllegalStateException(\n        \"FunctionDescription not persisted (null id): \" + func.getFunctionName());\n}\nreturn callgraphTable.queryCallgraphRows(func, true);","typeGuard":"// Narrows a FunctionDescription to one guaranteed persisted.\npublic static FunctionDescription requirePersisted(FunctionDescription f) {\n    if (f.getId() == null) {\n        throw new IllegalStateException(\"FunctionDescription has no row id: \" + f.getFunctionName());\n    }\n    return f;\n}","tryCatchPattern":null,"preventionTips":["Always insert/query functions through the database before using their id.","After insert, verify the returned generated id is set on the object.","Never pass in-memory-only FunctionDescriptions to table queries."],"tags":["bsim","callgraph","null-id","function-description","sql-exception"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}