lionsoul2014/ip2region · error

incomplete read: readed bytes should be %d

Error message

incomplete read: readed bytes should be %d

What it means

After seeking to 0, LoadHeader reads HeaderInfoLength (256) bytes into a buffer. If the reader returned fewer bytes than the buffer length (rLen != len(buff)), the header is truncated/short and this error is thrown. It guarantees the caller never gets a partially filled Header.

Source

Thrown at binding/golang/xdb/util.go:201

	return Verify(handle)
}

// LoadHeader load the header info from the specified handle
func LoadHeader(handle io.ReadSeeker) (*Header, error) {
	_, err := handle.Seek(0, 0)
	if err != nil {
		return nil, fmt.Errorf("seek to the header: %w", err)
	}

	var buff = make([]byte, HeaderInfoLength)
	rLen, err := handle.Read(buff)
	if err != nil {
		return nil, err
	}

	if rLen != len(buff) {
		return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
	}

	return NewHeader(buff)
}

// LoadHeaderFromFile load header info from the specified db file path
func LoadHeaderFromFile(dbFile string) (*Header, error) {
	handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600)
	if err != nil {
		return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err)
	}
	defer handle.Close()

	header, err := LoadHeader(handle)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to c1a1fc7d59)

Solutions

  1. Re-download or regenerate the .xdb file — verify it is complete (e.g. compare file size or checksum with the publisher).
  2. Check file size with os.Stat before calling; it must be at least HeaderInfoLength (256) bytes.
  3. Use LoadHeaderFromBuff only when you genuinely hold a full header buffer, and never truncate the file first.

Example fix

// before
header, err := xdb.LoadHeader(f) // f points at a truncated file
// after
fi, _ := f.Stat()
if fi.Size() < int64(xdb.HeaderInfoLength) {
    return fmt.Errorf("xdb file too small: %d bytes", fi.Size())
}
header, err := xdb.LoadHeader(f)
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(dbFile)
if err != nil { return err }
if fi.Size() < int64(xdb.HeaderInfoLength) {
    return fmt.Errorf("xdb file too small: %d bytes", fi.Size())
}

Type guard

func hasCompleteHeader(buf []byte) bool {
    return len(buf) >= xdb.HeaderInfoLength
}

Try / catch

header, err := xdb.LoadHeader(handle)
if err != nil {
    if strings.Contains(err.Error(), "incomplete read") {
        return fmt.Errorf("xdb file is truncated; re-download it")
    }
    return err
}

Prevention

When it happens

Trigger: Calling LoadHeader on a file/reader shorter than 256 bytes, or a reader that returns a short read at EOF — e.g. an empty or truncated .xdb file, or a bytes.Reader constructed from a partial header buffer.

Common situations: Incomplete download of the ip2region.xdb file; a zero-byte file created by a failed generator run; passing a buffer holding only part of the xdb to LoadHeader instead of LoadHeaderFromBuff.

Related errors


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