sipeed/picoclaw · error

image exceeds %d byte limit

Error message

image exceeds %d byte limit

What it means

Thrown by validateInlineImageDataURL in the pico channel when an inline data:image/...;base64,... payload would decode to more than config.DefaultMaxMediaSize (20 MB, defined at pkg/config/config.go:452). The check uses base64.StdEncoding.DecodedLen(len(data)), i.e. the upper-bound decoded size of the base64 body, not the raw string length. The library enforces this to keep pico payloads (and the peer's upload) within a fixed media budget.

Source

Thrown at pkg/channels/pico/pico.go:1407

	if !strings.HasPrefix(mediaURL, "data:image/") {
		return fmt.Errorf("only inline image data URLs are supported")
	}

	header, data, found := strings.Cut(mediaURL, ",")
	if !found || strings.TrimSpace(data) == "" {
		return fmt.Errorf("image data URL is malformed")
	}
	if !strings.Contains(header, ";base64") {
		return fmt.Errorf("image data URL must be base64 encoded")
	}
	mimeType, _, _ := strings.Cut(strings.TrimPrefix(header, "data:"), ";")
	if _, ok := allowedInlineImageMIMETypes[mimeType]; !ok {
		return fmt.Errorf("unsupported image format: %s", mimeType)
	}

	data = strings.TrimSpace(data)
	if base64.StdEncoding.DecodedLen(len(data)) > config.DefaultMaxMediaSize {
		return fmt.Errorf("image exceeds %d byte limit", config.DefaultMaxMediaSize)
	}
	if _, err := base64.StdEncoding.DecodeString(data); err != nil {
		return fmt.Errorf("invalid base64 image data")
	}

	return nil
}

// setContextUsagePayload adds context window usage stats to a pico payload.
func setContextUsagePayload(payload map[string]any, u *bus.ContextUsage) {
	if u == nil {
		return
	}
	payload["context_usage"] = map[string]any{
		"used_tokens":         u.UsedTokens,
		"total_tokens":        u.TotalTokens,
		"history_tokens":      u.HistoryTokens,
		"compress_at_tokens":  u.CompressAtTokens,

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Downscale or re-encode the image (JPEG/WebP quality ~80) so the decoded size is under 20 MB before building the data URL.
  2. Send the image as a URL reference or media ref instead of an inline base64 data URL, if the pico flow supports it.
  3. If you control the build, adjust config.DefaultMaxMediaSize (pkg/config/config.go:452) — but the remote pico peer enforces its own limit too.
  4. Check for accidental double-base64 encoding (data that is already base64 being encoded again), which inflates size ~33%.

Example fix

// before: raw 40 MB screenshot inlined directly
dataURL := "data:image/png;base64," + base64.StdEncoding.EncodeToString(rawPNG)

// after: keep the decoded size under the 20 MB limit first
const max = 20 * 1024 * 1024 // config.DefaultMaxMediaSize
if len(rawPNG) > max {
    rawPNG = downscaleAndReencode(rawPNG) // or return an error / use a URL ref
}
dataURL := "data:image/png;base64," + base64.StdEncoding.EncodeToString(rawPNG)
Defensive patterns

Strategy: validation

Validate before calling

// before sending, check the decoded size against the same limit the validator uses
const maxMedia = 20 * 1024 * 1024 // config.DefaultMaxMediaSize
func tooLarge(dataURL string) bool {
    if _, body, ok := strings.Cut(dataURL, ","); ok {
        return base64.StdEncoding.DecodedLen(len(strings.TrimSpace(body))) > maxMedia
    }
    return false
}

Try / catch

// after send: if err != nil && strings.Contains(err.Error(), "byte limit") -> tell the sender to shrink the image; do not retry unchanged

Prevention

When it happens

Trigger: Calling the pico send path with an OutboundMessage media entry whose data URL body decodes to >20971520 bytes; e.g. embedding a 30 MB PNG as base64 (base64 inflates it ~33% more on the wire). DecodedLen(len(data)) is computed on the trimmed base64 body after the comma in the data URL.

Common situations: Agents or tools inlining screenshots/photos as data URLs without downscaling; pasting a base64 image copied from an HTML page; switching from URL-referenced media to inline media; lowering/raising DefaultMaxMediaSize in a fork and forgetting the pico validator uses the same constant.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/486d38fa0925b6dd. Report an issue: GitHub.