{"record":{"id":"ec9fe476d2d7bc8c","repo":"Tencent/WeKnora","slug":"failed-to-upload-bytes-to-obs-w","errorCode":null,"errorMessage":"failed to upload bytes to OBS: %w","messagePattern":"failed to upload bytes to OBS: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/file/obs.go","lineNumber":316,"sourceCode":"\t\t\tobjectKey = fmt.Sprintf(\"temp/%d/%s%s\", tenantID, uuid.New().String(), ext)\n\t\t}\n\t} else {\n\t\tif s.pathPrefix != \"\" {\n\t\t\tobjectKey = fmt.Sprintf(\"%s/%d/%s%s\", s.pathPrefix, tenantID, uuid.New().String(), ext)\n\t\t} else {\n\t\t\tobjectKey = fmt.Sprintf(\"%d/%s%s\", tenantID, uuid.New().String(), ext)\n\t\t}\n\t}\n\n\t_, err := s.client.PutObject(ctx, &s3.PutObjectInput{\n\t\tBucket:      aws.String(s.bucketName),\n\t\tKey:         aws.String(objectKey),\n\t\tBody:        strings.NewReader(string(data)),\n\t\tContentType: aws.String(\"application/octet-stream\"),\n\t\tACL:         \"public-read\",\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to upload bytes to OBS: %w\", err)\n\t}\n\n\tprefix := s.getPrifix()\n\tif s.proxyDomain != \"\" {\n\t\treturn fmt.Sprintf(\"%s%s\", prefix, objectKey), nil\n\t}\n\treturn fmt.Sprintf(\"%s%s/%s\", prefix, s.bucketName, objectKey), nil\n}\n","sourceCodeStart":298,"sourceCodeEnd":325,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/file/obs.go#L298-L325","documentation":"OBS PutObject failed while uploading the in-memory byte payload (public-read ACL, temp or tenant-prefixed key) to OBS, so the bytes were not persisted; permissions, quota, or connectivity causes are wrapped in the error.","triggerScenarios":"PutObject with Body=strings.NewReader(data) fails on network errors, invalid credentials, missing PutObject permission, bucket not existing, or payload too large for available memory/network stability.","commonSituations":"AK/SK rotated but config not updated; bucket policy denying public-read ACL (ObjectOwnership ACLs disabled → ACL not permitted); endpoint/region misconfig; transient network drop.","solutions":["Unwrap the error: if it mentions ACL, the bucket has ACLs disabled (BucketOwnerEnforced) — remove the ACL: \"public-read\" field or enable ACLs","Verify credentials, endpoint, region and bucketName config","Check the credentials have s3:PutObject on the target prefix","Retry transient network errors with backoff; the objectKey is deterministic per call so retries are safe"],"exampleFix":"// before\nif err != nil { return \"\", fmt.Errorf(\"failed to upload bytes to OBS: %w\", err) }\n// after\nif err != nil {\n    if strings.Contains(err.Error(), \"ACL\") || strings.Contains(err.Error(), \"AccessControlListNotSupported\") {\n        // retry without ACL\n        return s.putBytesWithoutACL(ctx, objectKey, data)\n    }\n    return \"\", fmt.Errorf(\"failed to upload bytes to OBS: %w\", err)\n}","handlingStrategy":"retry","validationCode":"if len(data) == 0 { return errors.New(\"nothing to upload\") }\nif bucketName == \"\" || endpoint == \"\" { return errors.New(\"OSS/OBS config incomplete\") }","typeGuard":null,"tryCatchPattern":"path, err := svc.SaveBytes(ctx, tenantID, kid, data)\nif err != nil {\n    if isRetryableNetErr(err) {\n        path, err = svc.SaveBytes(ctx, tenantID, kid, data)\n    }\n    if err != nil {\n        return fmt.Errorf(\"obs bytes upload failed: %w\", err)\n    }\n}","preventionTips":["If the bucket has ACLs disabled, drop the public-read ACL field from uploads","Pre-flight HeadBucket at startup to catch bad endpoints/credentials early","Keep payloads bounded; very large byte slices are fragile over one PutObject"],"tags":["obs","s3","upload","acl"],"backgroundTag":"object-storage-upload-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}