{"record":{"id":"298a2f559dd0b092","repo":"Tencent/WeKnora","slug":"save-w","errorCode":null,"errorMessage":"save: %w","messagePattern":"save: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/image_resolver.go","lineNumber":812,"sourceCode":"\n\tif isIconImage(data) {\n\t\treturn nil, errRemoteImageIsIcon\n\t}\n\n\tif whitelisted {\n\t\treturn &remoteImageResult{MimeType: mimeType, KeepOriginalURL: true}, nil\n\t}\n\n\text := extFromMime(mimeType)\n\tif ext == \"\" {\n\t\text = extFromURLPath(imgURL)\n\t}\n\tif ext == \"\" {\n\t\text = \".png\" // safe default\n\t}\n\tservingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"save: %w\", err)\n\t}\n\treturn &remoteImageResult{ServingURL: servingURL, MimeType: mimeType}, nil\n}\n\n// isRemoteHTTPURL reports whether raw is an absolute http(s) URL.\n//\n// The comparison is deliberately byte-exact. Downstream fetchers compare the\n// scheme the same way, so anything accepted here has to be spelled the way they\n// expect; per-syntax normalization belongs in the SrcOf of the scan that needs\n// it, not in this predicate.\nfunc isRemoteHTTPURL(raw string) bool {\n\treturn strings.HasPrefix(raw, \"http://\") || strings.HasPrefix(raw, \"https://\")\n}\n\n// remotePassSpec describes one scan of a document: which references it matches,\n// where the URL sits inside a match, and how to turn the raw document bytes into\n// the URL to request.\ntype remotePassSpec struct {","sourceCodeStart":794,"sourceCodeEnd":830,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/image_resolver.go#L794-L830","documentation":"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.","triggerScenarios":"fetchAndStoreRemoteImage calls fileSvc.SaveBytes and it errors: storage backend unavailable, tenant bucket missing, permission denied, quota exceeded, or disk full.","commonSituations":"S3/OSS/minio credentials misconfigured or expired, storage quota exhausted for the tenant, object storage outage, network partition to storage backend, invalid tenantID.","solutions":["Unwrap the error and check the storage backend's specific failure","Verify storage service credentials, endpoint, and bucket configuration","Check tenant storage quota and available disk space","Confirm tenantID is valid and the tenant's storage location is provisioned"],"exampleFix":"// before\nservingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)\nif err != nil { return nil, fmt.Errorf(\"save: %w\", err) }\n// after\nservingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)\nif err != nil {\n    return nil, fmt.Errorf(\"save image for tenant %s: %w\", tenantID, err) // add tenant context\n}","handlingStrategy":"try-catch","validationCode":"// verify storage backend is writable before processing\nif err := fileSvc.Ping(ctx); err != nil {\n    return fmt.Errorf(\"storage backend unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"res, err := resolver.fetchAndStoreRemoteImage(ctx, imgURL, tenantID)\nif err != nil {\n    if strings.HasPrefix(err.Error(), \"save:\") {\n        // storage-side failure: check backend health/quota, queue for retry\n        return fmt.Errorf(\"persist image failed (check storage config/quota): %w\", err)\n    }\n    return err\n}","preventionTips":["Monitor storage backend health and quotas per tenant","Validate storage credentials and bucket provisioning at startup","Set up alerting for storage save failures","Confirm tenantID validity before processing"],"tags":["storage","persistence","image","io"],"backgroundTag":"file-save-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}