v2rayA/v2rayA · error

read frame body: %w

Error message

read frame body: %w

What it means

While scanning a .dat geosite file frame-by-frame, io.ReadFull failed to read the announced bodyLen bytes of a frame body. The file is either truncated/corrupt or the framing is wrong, so loadGeositeTag aborts reading this file.

Source

Thrown at core/main/geosite.go:144

		}
		if tagByte != 0x0a {
			// Not the expected frame format — skip.
			continue
		}

		// Read the varint length of the message body.
		bodyLen, err := binary.ReadUvarint(br)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, fmt.Errorf("read frame length: %w", err)
		}

		// Read the message body.
		body := make([]byte, bodyLen)
		if _, err := io.ReadFull(br, body); err != nil {
			return nil, fmt.Errorf("read frame body: %w", err)
		}

		// Unmarshal as GeoSite and check code.
		var site geodata.GeoSite
		if err := proto.Unmarshal(body, &site); err != nil {
			// Skip entries we can't parse.
			continue
		}

		if site.Code != tag && site.Code != tagUpper {
			continue
		}

		// Found matching entry — cache and return.
		domains := site.Domain
		geositeCache.mu.Lock()
		geositeCache.data[cacheKey] = domains
		geositeCache.mu.Unlock()

View on GitHub (pinned to 71e5442fc5)

Solutions

  1. Re-download / replace the geosite .dat file with a fresh, complete copy
  2. Verify file size and checksum against the official release
  3. Rebuild the .dat from source with a matching geodata protocol version
  4. Check the configured geosite path points to the intended file, not a truncated leftover

Example fix

// before
body := make([]byte, bodyLen)
if _, err := io.ReadFull(br, body); err != nil {
	return nil, fmt.Errorf("read frame body: %w", err)
}
// after
// redeploy a complete geosite.dat first, e.g.:
// curl -fLo geosite.dat https://example.com/geosite.dat && sha256sum -c geosite.dat.sha256
body := make([]byte, bodyLen)
if _, err := io.ReadFull(br, body); err != nil {
	return nil, fmt.Errorf("read frame body (file may be truncated/corrupt): %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// verify the geosite file before loading
st, err := os.Stat(geositePath)
if err != nil || st.Size() < 1024 { return fmt.Errorf("geosite file missing or truncated: %s", geositePath) }
// optional: verify sha256 against the release checksum

Try / catch

tags, err := loadGeositeTag(path, tag)
if err != nil {
	if strings.Contains(err.Error(), "read frame") {
		// file corrupt: re-download before giving up
	}
	return nil, err
}

Prevention

When it happens

Trigger: io.ReadFull(br, body) returns fewer than bodyLen bytes: the geosite .dat file was truncated during download, is corrupt on disk, or the declared frame length exceeds remaining file data.

Common situations: Interrupted download of geosite.dat left a partial file; disk corruption; a custom-built geosite.dat produced with a mismatched protobuf/framing version; mounted file cut short in a container image.

Related errors


AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05). Data as JSON: /api/errors/8cb0f690796ee1d7. Report an issue: GitHub.