lionsoul2014/ip2region · critical · Error

incomplete read (${rBytes} read, ${header.HeaderInfoLength}

Error message

incomplete read (${rBytes} read, ${header.HeaderInfoLength} expected)

What it means

loadHeader reads the fixed-size header block (HeaderInfoLength bytes) from offset 0 of an open xdb file descriptor. If fs.readSync returns fewer bytes than the header requires, the file is too small or truncated, and the library throws with the actual vs expected byte counts.

Source

Thrown at binding/javascript/util.js:342

    }

    let ipVer = h.ipVersion;
    if (ipVer == XdbIPv4Id) {
        return IPv4;
    } else if (ipVer == XdbIPv6Id) {
        return IPv6;
    } else {
        return null;
    }
}

// ---

export function loadHeader(fd) {
    const buffer = Buffer.alloc(HeaderInfoLength);
    const rBytes = fs.readSync(fd, buffer, 0, HeaderInfoLength, 0);
    if (rBytes != HeaderInfoLength) {
        throw new Error(`incomplete read (${rBytes} read, ${header.HeaderInfoLength} expected)`);
    }
    return new Header(buffer);
}

export function loadHeaderFromFile(dbPath) {
    const fd = fs.openSync(dbPath, "r");
    const header = loadHeader(fd);
    fs.closeSync(fd);
    return header;
}

export function loadVectorIndex(fd) {
    const vBytes = VectorIndexCols * VectorIndexRows * VectorIndexSize;
    const buffer = Buffer.alloc(vBytes);
    const rBytes = fs.readSync(fd, buffer, 0, vBytes, HeaderInfoLength);
    if (rBytes != vBytes) {
        throw new Error(`incomplete read (${rBytes} read, ${vBytes} expected)`);
    }

View on GitHub (pinned to c1a1fc7d59)

Solutions

  1. Re-download or re-copy the xdb data file and verify its size/checksum against the official release.
  2. Confirm the path passed to loadHeaderFromFile/Searcher points at a genuine xdb v2/v3 data file (starts with the expected magic).
  3. Check disk space and that the file finished writing (no in-progress producer).
  4. Compare fs.fstatSync(fd).size with HeaderInfoLength before calling to fail fast with a clearer message.

Example fix

// before
const header = loadHeader(fd); // throws on truncated file
// after
const size = fs.fstatSync(fd).size;
if (size < HeaderInfoLength) throw new Error(`${dbPath} truncated: ${size} bytes`);
const header = loadHeader(fd);
Defensive patterns

Strategy: validation

Validate before calling

const fd = fs.openSync(dbPath, 'r');
if (fs.fstatSync(fd).size < HeaderInfoLength)
  throw new Error(`${dbPath} is ${fs.fstatSync(fd).size} bytes; not a valid xdb file`);

Try / catch

try {
  const header = loadHeaderFromFile(dbPath);
} catch (e) {
  if (String(e.message).includes('incomplete read')) {
    throw new Error(`xdb file ${dbPath} is truncated; re-download it`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling loadHeader(fd) / header() on a file shorter than HeaderInfoLength — an empty file, a partially downloaded/copied xdb, a wrong file passed in, or a fd already at EOF due to reuse assumptions (readSync here is positioned at 0, so mainly file size matters).

Common situations: Interrupted download or rsync of the .xdb data file; mounting a volume where the file was replaced mid-read; pointing the searcher at a config/log file by mistake.

Related errors


AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02). Data as JSON: /api/errors/24dd709efa9771cc. Report an issue: GitHub.