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

  1. Inspect the wrapped error: use errors.Is(err, target) / errors.As on the chain, or gcerrors.Code(err) to classify (NotFound, PermissionDenied, ...).
  2. Reproduce the underlying driver failure directly (check the file/S3 resource for that key).
  3. 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

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


AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15). Data as JSON: /api/errors/5122a43123b97fc4. Report an issue: GitHub.