googleapis/mcp-toolbox · error

range %q must start with 'bytes='

Error message

range %q must start with 'bytes='

What it means

parseRange validates the optional 'range' parameter of cloudstorage-read-object, which must be an HTTP byte-range header value. If a non-empty range does not begin with the literal prefix 'bytes=', Invoke returns this error before calling the GCS API. It mirrors the RFC 7233 requirement that Range headers start with 'bytes='.

Source

Thrown at internal/tools/cloudstorage/cloudstoragereadobject/cloudstoragereadobject.go:165

	return resp, nil
}

// parseRange converts an HTTP Range header value into (offset, length) args for
// storage.ObjectHandle.NewRangeReader, where length == -1 means "read to end".
// Supported forms:
//
//	""           → (0, -1)       // full object
//	"bytes=0-9"  → (0, 10)       // first 10 bytes
//	"bytes=10-"  → (10, -1)      // from byte 10 to end
//	"bytes=-N"   → (-N, -1)      // last N bytes
func parseRange(rangeSpec string) (offset int64, length int64, err error) {
	if rangeSpec == "" {
		return 0, -1, nil
	}

	spec := strings.TrimSpace(rangeSpec)
	if !strings.HasPrefix(spec, "bytes=") {
		return 0, 0, fmt.Errorf("range %q must start with 'bytes='", rangeSpec)
	}
	spec = strings.TrimPrefix(spec, "bytes=")

	dash := strings.IndexByte(spec, '-')
	if dash < 0 {
		return 0, 0, fmt.Errorf("range %q is missing '-'", rangeSpec)
	}

	startStr := spec[:dash]
	endStr := spec[dash+1:]

	switch {
	case startStr == "" && endStr == "":
		return 0, 0, fmt.Errorf("range %q requires at least one bound", rangeSpec)

	case startStr == "":
		n, parseErr := strconv.ParseInt(endStr, 10, 64)
		if parseErr != nil || n <= 0 {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Prefix the value with 'bytes=', e.g. 'bytes=0-999', 'bytes=-500', or 'bytes=500-'
  2. If no range is needed, omit the range parameter or pass an empty string to read the full object
  3. Trim stray labels/units around the value before sending

Example fix

// before
{ "bucket": "my-bucket", "object": "f.txt", "range": "0-999" }
// after
{ "bucket": "my-bucket", "object": "f.txt", "range": "bytes=0-999" }
Defensive patterns

Strategy: validation

Validate before calling

func validRange(r string) error {
    if r == "" {
        return nil
    }
    if !strings.HasPrefix(r, "bytes=") {
        return fmt.Errorf("range %q must start with 'bytes='", r)
    }
    spec := strings.TrimPrefix(r, "bytes=")
    if !strings.Contains(spec, "-") {
        return fmt.Errorf("range %q is missing '-'", r)
    }
    return nil
}

Prevention

When it happens

Trigger: Calling the read-object tool with range set to values like '0-999', 'byte 0-99', '0-99 bytes', or any string missing the 'bytes=' prefix; whitespace-only variants are trimmed, so '0-999' still fails.

Common situations: Passing just 'start-end' thinking the tool adds the prefix; sending a Content-Range style value; client UIs stripping the prefix; non-English locale docs showing ranges without 'bytes='.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/7fb74cb3973ebecf. Report an issue: GitHub.