{"record":{"id":"c015e388ae5a433d","repo":"Tencent/WeKnora","slug":"failed-to-upload-file-to-obs-w","errorCode":null,"errorMessage":"failed to upload file to OBS: %w","messagePattern":"failed to upload file to OBS: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/file/obs.go","lineNumber":182,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"failed to open file: %w\", err)\n\t}\n\tdefer src.Close()\n\n\tcontentType := file.Header.Get(\"Content-Type\")\n\tif contentType == \"\" {\n\t\tcontentType = \"application/octet-stream\"\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:          src,\n\t\tContentLength: aws.Int64(file.Size),\n\t\tContentType:   aws.String(contentType),\n\t\t// ACL:           \"private\",\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to upload file to OBS: %w\", err)\n\t}\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\nfunc (s *obsFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {\n\tobjectKey, err := s.parseObsFilePath(filePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\toutput, err := s.client.GetObject(ctx, &s3.GetObjectInput{\n\t\tBucket: aws.String(s.bucketName),\n\t\tKey:    aws.String(objectKey),\n\t})","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/file/obs.go#L164-L200","documentation":"OBS PutObject failed while uploading the opened multipart file (with default or octet-stream content type) to the generated object key, so the file was not stored; permissions, quota, or connectivity failures are wrapped in the cause.","triggerScenarios":"PutObject called with Body=src, ContentLength and ContentType; fails on network errors, invalid/expired credentials, missing write permission on the bucket, wrong region/endpoint, or content-length mismatch on the reader.","commonSituations":"Wrong OBS endpoint or region in config; IAM/AK-SK lacking PutObject permission; VPC endpoint or firewall blocking traffic; intermittent network failure on large uploads; clock skew breaking signature.","solutions":["Unwrap the error and check its code: credentials (SignatureDoesNotMatch/AccessDenied) vs network vs NoSuchBucket","Verify endpoint, region, bucketName and AK/SK in the OBS service config","Confirm the bucket exists and the credentials have s3:PutObject permission","For transient network errors (timeouts, connection reset), retry with backoff; make SaveFile idempotent by generating a new objectKey per attempt"],"exampleFix":"// before\nif err != nil { return \"\", fmt.Errorf(\"failed to upload file to OBS: %w\", err) }\n// after\nif err != nil {\n    var ae smithy.APIError\n    if errors.As(err, &ae) && (ae.ErrorCode() == \"AccessDenied\" || ae.ErrorCode() == \"SignatureDoesNotMatch\") {\n        return \"\", fmt.Errorf(\"obs credentials/permissions problem: %w\", err)\n    }\n    if isRetryableNetErr(err) {\n        return s.SaveFile(ctx, tenantID, knowledgeID, file) // new objectKey, retry once\n    }\n    return \"\", fmt.Errorf(\"failed to upload file to OBS: %w\", err)\n}","handlingStrategy":"retry","validationCode":"if endpoint == \"\" || bucketName == \"\" || accessKey == \"\" || secretKey == \"\" {\n    return errors.New(\"OBS config incomplete before SaveFile\")\n}","typeGuard":null,"tryCatchPattern":"path, err := svc.SaveFile(ctx, tenantID, kid, fh)\nif err != nil {\n    var retryable interface{ RetryableError() bool }\n    if errors.As(err, &retryable) && retryable.RetryableError() {\n        path, err = svc.SaveFile(ctx, tenantID, kid, fh) // new objectKey per attempt\n    }\n    if err != nil {\n        return fmt.Errorf(\"obs upload failed: %w\", err)\n    }\n}","preventionTips":["Pre-flight the bucket and credentials at startup (HeadBucket)","Grant least-privilege s3:PutObject on the app's prefix","Use https endpoints with correct region; keep clock in sync for signatures"],"tags":["obs","s3","upload","network"],"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"}