pocketbase/pocketbase · info
[key: %s] %w
Error message
[key: %s] %w
What it means
This is not a distinct failure but the portable blob package's error-wrapping step: when an operation fails and a key is known, the driver error is normalized (via NormalizeError / gcerrors) and prefixed with "[key: <key>]" using %w, so the original error stays unwrappable. Seeing this message means some underlying driver operation on that key failed; the real cause is the wrapped error.
Source
Thrown at tools/filesystem/blob/bucket.go:727
return wrapError(b.drv, b.drv.Close(), "")
}
func wrapError(b Driver, err error, key string) error {
if err == nil {
return nil
}
// don't wrap or normalize EOF errors since there are many places
// in the standard library (e.g. io.ReadAll) that rely on checks
// such as "err == io.EOF" and they will fail
if errors.Is(err, io.EOF) {
return err
}
err = b.NormalizeError(err)
if key != "" {
err = fmt.Errorf("[key: %s] %w", key, err)
}
return err
}
View on GitHub (pinned to 5d217ddb50)
Solutions
- Inspect the wrapped error: use errors.Is(err, target) / errors.As on the chain, or gcerrors.Code(err) to classify (NotFound, PermissionDenied, ...).
- Reproduce the underlying driver failure directly (check the file/S3 resource for that key).
- If you string-matched error text before, switch to gcerrors.Code-based handling.
Example fix
// before
if strings.Contains(err.Error(), "not found") { ... }
// after
if gcerrors.Code(err) == gcerrors.NotFound { ... }
// or: if errors.Is(err, blob.ErrObjectNotFound) { ... } Defensive patterns
Strategy: try-catch
Type guard
func isBlobNotFound(err error) bool { return gcerrors.Code(err) == gcerrors.NotFound } Try / catch
if err := bucket.Read(...); err != nil {
switch gcerrors.Code(err) {
case gcerrors.NotFound:
// handle missing object
default:
// log full chain: err (already wraps driver cause with [key: ...])
}
} Prevention
- Always branch on gcerrors.Code / errors.Is, never on message text.
- Log the full error chain (err plus %v of wrapped cause) to see the driver-level reason.
- Keep keys in log context separately; the [key: ...] prefix is a hint, not the diagnosis.
When it happens
Trigger: Any wrapped failure path in Bucket (Read, Write, Close, Copy, Delete, Attributes, List) where the helper is called with a non-empty key — e.g. driver returns NotFound, permission, or I/O error for that key. The io.EOF case is deliberately passed through unwrapped so stdlib checks like err == io.EOF keep working.
Common situations: Developers see only the prefix in logs and misdiagnose it; the actual problem is the wrapped driver error (file missing, S3 403, connection reset). Also hit when string-matching errors instead of using errors.Is/errors.As and gcerrors.Code.
Related errors
- Delete key must be a valid UTF-8 string: %q
- Seek resulted in invalid offset %d, using 0
- the WriterOptions.ContentMD5 you specified (%X) did not matc
- file extension %q is reserved
- invalid_json
AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15).
Data as JSON: /api/errors/5122a43123b97fc4.
Report an issue: GitHub.