henrygd/beszel · warning

%s returned negative bytes: %d

Error message

%s returned negative bytes: %d

What it means

ReadStringFileLimited reads up to maxSize bytes from the file at path and returns the trimmed contents. A negative read count violates the io.Reader contract (n < 0 should only accompany a non-nil error, which is already handled above), so the function defensively rejects it rather than returning corrupted string data.

Source

Thrown at agent/utils/utils.go:74

	return strings.TrimSpace(string(b)), true
}

// ReadStringFileLimited reads a file into a string with a maximum size (in bytes) to avoid
// allocating large buffers and potential panics with pseudo-files when the size is misreported.
func ReadStringFileLimited(path string, maxSize int) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer f.Close()

	buf := make([]byte, maxSize)
	n, err := f.Read(buf)
	if err != nil && err != io.EOF {
		return "", err
	}
	if n < 0 {
		return "", fmt.Errorf("%s returned negative bytes: %d", path, n)
	}
	return strings.TrimSpace(string(buf[:n])), nil
}

// FileExists reports whether the given path exists.
func FileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

// ReadUintFile parses a decimal uint64 value from a file.
func ReadUintFile(path string) (uint64, bool) {
	raw, ok := ReadStringFileOK(path)
	if !ok {
		return 0, false
	}
	parsed, err := strconv.ParseUint(raw, 10, 64)
	if err != nil {

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Close and reopen the file and retry the read; transient file-handle state is the most plausible cause.
  2. Check whether any custom io.Reader replaces os.File in this path and fix its Read to never return negative n.
  3. Report upstream if reproducible with a plain os.File — this indicates a runtime or filesystem driver bug.
  4. Log the raw (n, err) pair when this triggers to diagnose the offending reader.

Example fix

// before
n, err := f.Read(buf)
if n < 0 {
	return "", fmt.Errorf("%s returned negative bytes: %d", path, n)
}
// after
n, err := io.ReadFull(io.LimitReader(f, int64(maxSize)), buf)
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
	return "", err
} // n is never negative by construction
Defensive patterns

Strategy: validation

Validate before calling

// prefer bounded, contract-safe reads and stat before reading
if fi, err := os.Stat(path); err != nil || fi.Size() > int64(maxSize) {
	return fmt.Errorf("file %s missing or too large", path)
}

Type guard

func validReadCount(n int) bool { return n >= 0 && n <= maxSize }

Try / catch

s, err := utils.ReadStringFileLimited(path, maxSize)
if err != nil {
	if strings.Contains(err.Error(), "returned negative bytes") {
		// retry once with a fresh handle or fall back to os.ReadFile
	}
	return err
}

Prevention

When it happens

Trigger: f.Read(buf) returns n < 0 with a nil or EOF error — indicative of a misbehaving custom io.Reader or a corrupted file handle; os.File.Read never legitimately does this.

Common situations: Extremely rare; seen when a test/mock reader is substituted for os.File, under FUSE or exotic filesystem quirks, or while fuzzing. Indicates a reader implementation bug rather than a caller mistake.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/11cbdb88520545b1. Report an issue: GitHub.