NationalSecurityAgency/ghidra · error · IOException
Score file missing threshold lines
Error message
Score file missing threshold lines
What it means
Thrown by FileScoreCaching.loadCache() when the score file exists but is completely empty — the first readLine() returns null. The expected file format begins with two header lines (simThreshold then sigThreshold) followed by one line per executable (md5 + score). An empty or zero-byte file fails this invariant at the very first read.
Source
Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/FileScoreCaching.java:50
storageFile = new File(fileName);
cacheMap = null;
simThreshold = -1.0; // Negative indicates thresholds have not been configured
sigThreshold = -1.0;
}
private void loadCache() throws IOException {
if (cacheMap != null) {
return;
}
if (!storageFile.exists()) {
return; // File doesn't exist, it will get created on first commitSelfScore call
}
cacheMap = new TreeMap<String, Float>();
BufferedReader reader = new BufferedReader(new FileReader(storageFile));
String floatString = reader.readLine();
if (floatString == null) {
reader.close();
throw new IOException("Score file missing threshold lines");
}
simThreshold = Float.parseFloat(floatString);
floatString = reader.readLine();
if (floatString == null) {
reader.close();
throw new IOException("Score file missing threshold lines");
}
sigThreshold = Float.parseFloat(floatString);
floatString = reader.readLine();
while (floatString != null) {
String[] split = floatString.split(" ");
if (split.length != 2 || split[0].length() != 32) {
reader.close();
throw new IOException("Bad line in score file");
}
float val = Float.parseFloat(split[1]);
cacheMap.put(split[0], val);
floatString = reader.readLine();View on GitHub (pinned to d5f144c24d)
Solutions
- Delete the corrupt/empty cache file so it gets regenerated with valid header lines on the next commitSelfScore call.
- Call FileScoreCaching.resetStorage(simThresh, sigThresh) to delete the existing file and reinitialize thresholds.
- Investigate what created the empty file (failed process, manual touch) to prevent recurrence.
Example fix
// before — cache file exists but is empty FileScoreCaching cache = new FileScoreCaching(path); cache.getSelfScore(md5); // throws IOException "Score file missing threshold lines" // after FileScoreCaching cache = new FileScoreCaching(path); cache.resetStorage(simThresh, sigThresh); // deletes bad file, resets thresholds
Defensive patterns
Strategy: validation
Validate before calling
File cacheFile = new File(cachePath);
if (cacheFile.exists() && cacheFile.length() == 0) {
cacheFile.delete(); // remove empty file so it regenerates
} Try / catch
try {
cache.getSelfScore(md5);
} catch (LSHException e) {
if (e.getMessage().contains("threshold lines")) {
cache.resetStorage(simThresh, sigThresh);
// regenerate scores then retry
} else throw e;
} Prevention
- Validate the cache file has content before relying on it.
- Use resetStorage to clean corrupt files.
- Investigate what left the file empty (crashed process, manual touch).
When it happens
Trigger: The score cache file referenced by FileScoreCaching's constructor exists on disk but contains no data (e.g. created by a failed/touch command, truncated by a crash during write, or a race condition where the file was created but the header lines were never flushed).
Common situations: An interrupted previous run left a zero-byte cache file. A user manually created or truncated the cache file. A concurrent process or filesystem issue truncated the file between the existence check and the read.
Related errors
- Bad line in score file
- Could not recover cached scores: {e.getMessage()}
- Self-score not recorded for {md5}
- Could not commit self-score: {ex.getMessage()}
- Problems loading score cache: {e.getMessage()}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/392bac7fd979901d.
Report an issue: GitHub.