lionsoul2014/ip2region · critical · Error
incomplete read (${rBytes} read, ${stats.size} expected)
Error message
incomplete read (${rBytes} read, ${stats.size} expected) What it means
loadContent stats the fd and reads the entire file (stats.size bytes) from offset 0 into one Buffer for the ContentCache policy. If the read returns fewer bytes than fstat reported, the library throws rather than caching an incomplete copy of the data region.
Source
Thrown at binding/javascript/util.js:376
if (rBytes != vBytes) {
throw new Error(`incomplete read (${rBytes} read, ${vBytes} expected)`);
}
return buffer;
}
export function loadVectorIndexFromFile(dbPath) {
const fd = fs.openSync(dbPath, "r");
const vIndex = loadVectorIndex(fd);
fs.closeSync(fd);
return vIndex;
}
export function loadContent(fd) {
const stats = fs.fstatSync(fd);
const buffer = Buffer.alloc(stats.size);
const rBytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
if (rBytes != stats.size) {
throw new Error(`incomplete read (${rBytes} read, ${stats.size} expected)`);
}
return buffer;
}
export function loadContentFromFile(dbPath) {
const fd = fs.openSync(dbPath, "r");
const content = loadContent(fd);
fs.closeSync(fd);
return content;
}
// ---
// Verify if the current Searcher could be used to search the specified xdb file.
// Why do we need this check ?
// The future features of the xdb impl may cause the current searcher not able to work properly.
//
// @Note: You Just need to check this ONCE when the service startsView on GitHub (pinned to c1a1fc7d59)
Solutions
- Re-copy the xdb file, verify integrity (size/checksum), and restart or reload the searcher.
- Stop concurrent writers before loading, or atomically swap via rename and reopen the fd after.
- Retry the load — a transient short read often succeeds on the second attempt.
- Add a pre-check comparing fstatSync(fd).size against the minimum expected xdb size.
Example fix
// before
const buf = loadContent(fd); // short read -> throws
// after
let buf;
for (let i = 0; i < 3 && !buf; i++) {
try { buf = loadContent(fd); } catch (e) { if (!/incomplete read/.test(e.message)) throw e; }
}
if (!buf) throw new Error('xdb content repeatedly short-read; file may be truncated'); Defensive patterns
Strategy: retry
Validate before calling
const size = fs.fstatSync(fd).size;
if (size === 0) throw new Error('xdb file is empty');
// optionally: minimum plausible size check before full-content cache load Try / catch
try {
contentBuf = loadContent(fd);
} catch (e) {
if (String(e.message).includes('incomplete read')) {
// reopen the file (it may have been swapped) and retry once
fd = fs.openSync(dbPath, 'r');
contentBuf = loadContent(fd);
} else throw e;
} Prevention
- Deploy xdb updates atomically (write temp file + rename) and reopen fds after swap.
- Avoid loading content cache while the maker writes the same path.
- Monitor disk/filesystem health for network mounts serving the db.
When it happens
Trigger: loadContent(fd) / content() where the file shrinks between fstatSync and readSync (concurrent writer/replacer), a truncated file, or I/O returning short reads on an unreliable/network filesystem.
Common situations: Deploy systems that swap the .xdb via rename while searchers hold open fds; NFS/EFS hiccups; file being regenerated by the xdb maker while the app starts.
Related errors
- incomplete read (${rBytes} read, ${header.HeaderInfoLength}
- incomplete read (${rBytes} read, ${vBytes} expected)
- invalid bytes ip, not a Buffer
- invalid bytes ip with length not 4 or 16
- invalid structure version ${header.version}
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/eb3a14be0408b621.
Report an issue: GitHub.