Tencent/WeKnora · error

save: %w

Error message

save: %w

What it means

This error wraps a failure from fileSvc.SaveBytes when persisting a downloaded remote image to storage. The image bytes were fetched successfully but could not be saved under a generated UUID filename for the tenant.

Source

Thrown at internal/infrastructure/docparser/image_resolver.go:812

	if isIconImage(data) {
		return nil, errRemoteImageIsIcon
	}

	if whitelisted {
		return &remoteImageResult{MimeType: mimeType, KeepOriginalURL: true}, nil
	}

	ext := extFromMime(mimeType)
	if ext == "" {
		ext = extFromURLPath(imgURL)
	}
	if ext == "" {
		ext = ".png" // safe default
	}
	servingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)
	if err != nil {
		return nil, fmt.Errorf("save: %w", err)
	}
	return &remoteImageResult{ServingURL: servingURL, MimeType: mimeType}, nil
}

// isRemoteHTTPURL reports whether raw is an absolute http(s) URL.
//
// The comparison is deliberately byte-exact. Downstream fetchers compare the
// scheme the same way, so anything accepted here has to be spelled the way they
// expect; per-syntax normalization belongs in the SrcOf of the scan that needs
// it, not in this predicate.
func isRemoteHTTPURL(raw string) bool {
	return strings.HasPrefix(raw, "http://") || strings.HasPrefix(raw, "https://")
}

// remotePassSpec describes one scan of a document: which references it matches,
// where the URL sits inside a match, and how to turn the raw document bytes into
// the URL to request.
type remotePassSpec struct {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Unwrap the error and check the storage backend's specific failure
  2. Verify storage service credentials, endpoint, and bucket configuration
  3. Check tenant storage quota and available disk space
  4. Confirm tenantID is valid and the tenant's storage location is provisioned

Example fix

// before
servingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)
if err != nil { return nil, fmt.Errorf("save: %w", err) }
// after
servingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)
if err != nil {
    return nil, fmt.Errorf("save image for tenant %s: %w", tenantID, err) // add tenant context
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify storage backend is writable before processing
if err := fileSvc.Ping(ctx); err != nil {
    return fmt.Errorf("storage backend unavailable: %w", err)
}

Try / catch

res, err := resolver.fetchAndStoreRemoteImage(ctx, imgURL, tenantID)
if err != nil {
    if strings.HasPrefix(err.Error(), "save:") {
        // storage-side failure: check backend health/quota, queue for retry
        return fmt.Errorf("persist image failed (check storage config/quota): %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: fetchAndStoreRemoteImage calls fileSvc.SaveBytes and it errors: storage backend unavailable, tenant bucket missing, permission denied, quota exceeded, or disk full.

Common situations: S3/OSS/minio credentials misconfigured or expired, storage quota exhausted for the tenant, object storage outage, network partition to storage backend, invalid tenantID.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/298a2f559dd0b092. Report an issue: GitHub.