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
- Downscale or re-encode the image (JPEG/WebP quality ~80) so the decoded size is under 20 MB before building the data URL.
- Send the image as a URL reference or media ref instead of an inline base64 data URL, if the pico flow supports it.
- If you control the build, adjust config.DefaultMaxMediaSize (pkg/config/config.go:452) — but the remote pico peer enforces its own limit too.
- 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
- Downscale/re-encode images before inlining them as data URLs
- Prefer media refs or https URLs over inline base64 for large images
- Remember the limit applies to the DECODED size, not the base64 string length
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
- invalid base64 image data
- media too large
- unsupported wecom media type or size for %q
- ${label} must be a JSON object.
- ${label}.${key} must be a string.
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/486d38fa0925b6dd.
Report an issue: GitHub.