Tencent/WeKnora · error

failed to upload file to OBS: %w

Error message

failed to upload file to OBS: %w

What it means

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.

Source

Thrown at internal/application/service/file/obs.go:182

		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer src.Close()

	contentType := file.Header.Get("Content-Type")
	if contentType == "" {
		contentType = "application/octet-stream"
	}

	_, err = s.client.PutObject(ctx, &s3.PutObjectInput{
		Bucket:        aws.String(s.bucketName),
		Key:           aws.String(objectKey),
		Body:          src,
		ContentLength: aws.Int64(file.Size),
		ContentType:   aws.String(contentType),
		// ACL:           "private",
	})
	if err != nil {
		return "", fmt.Errorf("failed to upload file to OBS: %w", err)
	}
	prefix := s.getPrifix()
	if s.proxyDomain != "" {
		return fmt.Sprintf("%s%s", prefix, objectKey), nil
	}
	return fmt.Sprintf("%s%s/%s", prefix, s.bucketName, objectKey), nil
}

func (s *obsFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {
	objectKey, err := s.parseObsFilePath(filePath)
	if err != nil {
		return nil, err
	}

	output, err := s.client.GetObject(ctx, &s3.GetObjectInput{
		Bucket: aws.String(s.bucketName),
		Key:    aws.String(objectKey),
	})

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Unwrap the error and check its code: credentials (SignatureDoesNotMatch/AccessDenied) vs network vs NoSuchBucket
  2. Verify endpoint, region, bucketName and AK/SK in the OBS service config
  3. Confirm the bucket exists and the credentials have s3:PutObject permission
  4. For transient network errors (timeouts, connection reset), retry with backoff; make SaveFile idempotent by generating a new objectKey per attempt

Example fix

// before
if err != nil { return "", fmt.Errorf("failed to upload file to OBS: %w", err) }
// after
if err != nil {
    var ae smithy.APIError
    if errors.As(err, &ae) && (ae.ErrorCode() == "AccessDenied" || ae.ErrorCode() == "SignatureDoesNotMatch") {
        return "", fmt.Errorf("obs credentials/permissions problem: %w", err)
    }
    if isRetryableNetErr(err) {
        return s.SaveFile(ctx, tenantID, knowledgeID, file) // new objectKey, retry once
    }
    return "", fmt.Errorf("failed to upload file to OBS: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if endpoint == "" || bucketName == "" || accessKey == "" || secretKey == "" {
    return errors.New("OBS config incomplete before SaveFile")
}

Try / catch

path, err := svc.SaveFile(ctx, tenantID, kid, fh)
if err != nil {
    var retryable interface{ RetryableError() bool }
    if errors.As(err, &retryable) && retryable.RetryableError() {
        path, err = svc.SaveFile(ctx, tenantID, kid, fh) // new objectKey per attempt
    }
    if err != nil {
        return fmt.Errorf("obs upload failed: %w", err)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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