juicedata/juicefs · error

failed to get the first byte:, expect "h", but got %q, error

Error message

failed to get the first byte:, expect "h", but got %q, error: %s

What it means

This error is produced by the 'get partial object' benchmark case in `juicefs objbench` (cmd/objbench.go). The benchmark stores the object "hello" (5 bytes) and then issues a ranged GET of 1 byte at offset 0 via the object-storage abstraction (object.ObjectStorage.Get). If the returned data is not exactly "h" or the call returns an error, the case fails with this message. It signals that the backend does not honor partial (range) reads at the start of an object.

Source

Thrown at cmd/objbench.go:817

	})

	runCase("get non-exist", func(blob object.ObjectStorage) error {
		if _, err := blob.Get(ctx, "not_exists_file", 0, -1); err == nil {
			return fmt.Errorf("get not existed object should failed: %s", err)
		}
		return nil
	})

	runCase("get partial object", func(blob object.ObjectStorage) error {
		br := []byte("hello")
		if err := blob.Put(ctx, key, bytes.NewReader(br)); err != nil {
			return fmt.Errorf("put object failed: %s", err)
		}
		defer blob.Delete(ctx, key) //nolint:errcheck

		// get first
		if d, e := get(blob, key, 0, 1); e != nil || d != "h" {
			return fmt.Errorf(`failed to get the first byte:, expect "h", but got %q, error: %s`, d, e)
		}
		// get last
		if d, e := get(blob, key, 4, 1); e != nil || d != "o" {
			return fmt.Errorf(`failed to get the last byte: expect "o", but got %q, error: %s`, d, e)
		}
		// get last 3
		if d, e := get(blob, key, 2, 3); e != nil || d != "llo" {
			return fmt.Errorf(`failed to get the last three bytes: expect "llo", but got %q, error: %s`, d, e)
		}
		// get middle
		if d, e := get(blob, key, 2, 2); e != nil || d != "ll" {
			return fmt.Errorf(`failed to get two bytes: expect "ll", but got %q, error: %s`, d, e)
		}
		// get the end out of range
		if d, e := get(blob, key, 4, 2); e != nil || d != "o" {
			return warning(fmt.Errorf(`failed to get object with the end out of range, expect "o", but got %q, error: %s`, d, e))
		}
		// get the off out of range

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Inspect the error suffix (%s) to see the underlying storage error and fix that first (credentials, network, endpoint).
  2. If data is wrong, verify the backend honors Range requests: `aws s3api get-object --range bytes=0-0` against the same endpoint.
  3. Update or fix the custom object.ObjectStorage implementation so Get(off, size) slices correctly.
  4. Re-run only this case with `juicefs objbench --small-color=... `/ relevant flags or use `juicefs gc`-free single-case testing to confirm.

Example fix

// before (custom storage ignoring range)
func (s *myStore) Get(ctx, key string, off, limit int64) (io.ReadCloser, error) {
    return s.get(key, 0, -1) // returns whole object, d == "hello"
}
// after
func (s *myStore) Get(ctx, key string, off, limit int64) (io.ReadCloser, error) {
    return s.getRange(key, off, limit) // d == "h"
}
Defensive patterns

Strategy: validation

Validate before calling

// before running objbench against a backend, smoke-test ranged reads:
rc, err := blob.Get(ctx, key, 0, 1)
if err != nil { log.Fatalf("ranged get failed: %v", err) }
buf, _ := io.ReadAll(rc); rc.Close()
if len(buf) != 1 || buf[0] != 'h' { log.Fatalf("bad range read: %q", buf) }

Type guard

func isOneByte(d string, err error) bool { return err == nil && len(d) == 1 }

Try / catch

if d, e := get(blob, key, 0, 1); e != nil || d != "h" {
    log.Printf("partial get (first byte) failed: data=%q err=%v", d, e)
    // fall back to full-object read + slice
}

Prevention

When it happens

Trigger: Running `juicefs objbench` against an object storage whose Get(key, off=0, size=1) returns the wrong bytes (e.g. the whole object, empty data, or corrupted content) or returns a non-nil error such as 416/timeout/auth failure.

Common situations: Testing a custom or third-party ObjectStorage implementation that ignores the offset/limit parameters; an S3-compatible endpoint that mishandles Range headers; proxy/gateway layers that rewrite or truncate ranged GETs; stale or eventually-consistent reads right after Put.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/835a7eb7caad5e00. Report an issue: GitHub.