NationalSecurityAgency/ghidra · error · IllegalArgumentException
all function symbols are not from the same program
Error message
all function symbols are not from the same program
What it means
Thrown by the SFQueryInfo constructor when the function set contains symbols from more than one Program. The constructor locks in the first symbol's program and rejects any symbol whose getProgram() differs, because a single QueryNearest must run against one signature/address context. Third ordered check.
Source
Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/facade/SFQueryInfo.java:69
* @throws IllegalArgumentException if {@code functions} is {@code null}/empty or functions
* are from multiple programs.
*/
public SFQueryInfo(Set<FunctionSymbol> functions) {
if (functions == null) {
throw new IllegalArgumentException("Function list cannot be null");
}
if (functions.isEmpty()) {
throw new IllegalArgumentException("Function list cannot be empty");
}
this.functions = functions;
for (FunctionSymbol s : functions) {
if (program == null) {
program = s.getProgram();
}
else if (program != s.getProgram()) {
throw new IllegalArgumentException(
"all function symbols are not from the same program");
}
}
queryNearest = new QueryNearest();
bsimFilter = new BSimFilter();
preFilter = new PreFilter();
}
/**
* @return the program from which all queried functions are from
*/
public Program getProgram() {
return program;
}
/**
* Gets the threshold under which a potential similar function will not be matched. This
* threshold is for how similar the potential function is. This is a value from 0.0 to 1.0. The View on GitHub (pinned to d5f144c24d)
Solutions
- Partition the set by getProgram() and issue one SFQueryInfo per program.
- Scope selection gathering to the current/active program.
- Drop external/library symbols (different Program) from the set before construction.
Example fix
// before
Set<FunctionSymbol> mixed = gatherAcrossPrograms();
SFQueryInfo info = new SFQueryInfo(mixed);
// after
Map<Program, List<Set<FunctionSymbol>>> grouped = mixed.stream()
.collect(Collectors.groupingBy(FunctionSymbol::getProgram));
grouped.values().forEach(syms -> {
SFQueryInfo info = new SFQueryInfo(new HashSet<>(syms));
}); Defensive patterns
Strategy: validation
Validate before calling
Map<Program, Set<FunctionSymbol>> byProgram = functions.stream()
.collect(Collectors.groupingBy(FunctionSymbol::getProgram, Collectors.toSet()));
for (Set<FunctionSymbol> per : byProgram.values()) {
SFQueryInfo info = new SFQueryInfo(per);
} Type guard
static boolean singleProgram(Set<FunctionSymbol> fns) {
return fns.stream().map(FunctionSymbol::getProgram).distinct().count() <= 1;
} Try / catch
try {
new SFQueryInfo(functions);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("same program")) { /* split per program */ }
} Prevention
- Gather selection from the active program only.
- Partition mixed sets before constructing SFQueryInfo.
- Exclude external/library symbols from a different Program.
When it happens
Trigger: Passing a set assembled across multiple open programs, or mixing main-program symbols with external/library symbols that report a different Program.
Common situations: Cross-program selection; a script that aggregates symbols from several Program objects into one set; selection spanning a program and its imported library.
Related errors
- all function symbols are not from the same program
- Function list cannot be null
- Function list cannot be empty
- ExeSpecifier must provide either md5 or name
- Function list cannot be null
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/fb4a78ecd9649538.
Report an issue: GitHub.