Tencent/WeKnora · error

failed to upload bytes to OSS

Error message

failed to upload bytes to OSS: %w

What it means

This error is returned by ossFileService.SaveBytes when the PutObject call uploading the byte slice to OSS fails. It wraps the SDK error, so the OSS-level cause (auth, permissions, network, quota) is preserved. The content type is derived from the file extension via utils.GetContentTypeByExt before upload.

Solutions

  1. Unwrap the error to identify the OSS error code.
  2. Verify target bucket (main vs temp bucket when temp=true) exists and credentials have write access.
  3. Check network/endpoint configuration for the region the bucket lives in.
  4. For very large payloads, reduce size or add multipart support / compression before upload.
  5. Retry transient failures (RequestTimeout, 5xx) with backoff.

Example fix

// before
if err != nil {
    return "", fmt.Errorf("failed to upload bytes to OSS: %w", err)
}
// after
if err != nil {
    var retriable bool
    var netErr net.Error
    if errors.As(err, &netErr) { retriable = true }
    return "", fmt.Errorf("failed to upload bytes to OSS (retriable=%v): %w", retriable, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-checks before SaveBytes
if len(data) == 0 { return errors.New("empty payload") }
if temp && tempBucketName == "" { return errors.New("temp bucket not configured") }

Try / catch

path, err := svc.SaveBytes(ctx, data, tenantID, name, temp)
var svcErr *oss.ServiceError
if errors.As(err, &svcErr) {
    if isRetryableCode(svcErr.Code) { // RequestTimeout, InternalError, 5xx
        // retry with backoff
    }
}

Prevention

When it happens

Trigger: Calling SaveBytes with valid data but client.PutObject fails: expired credentials, missing oss:PutObject on the target bucket (main or temp bucket), network failure, bucket missing, or payload exceeding OSS/SDK size limits for a single PUT.

Common situations: Temp-bucket misconfiguration (SaveBytes with temp=true targeting a nonexistent temp bucket); oversized in-memory exports exceeding single-PUT limits; key rotation invalidating credentials mid-run; egress firewall rules blocking OSS endpoints.

Related errors


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

Appendix: source

Thrown at internal/application/service/file/oss.go:244

	targetBucket := s.bucketName
	client := s.client
	objectName := fmt.Sprintf("%s%d/exports/%s%s", s.pathPrefix, tenantID, uuid.New().String(), ext)

	if temp && s.tempClient != nil {
		targetBucket = s.tempBucketName
		client = s.tempClient
		objectName = fmt.Sprintf("exports/%d/%s%s", tenantID, uuid.New().String(), ext)
	}

	_, err = client.PutObject(ctx, &oss.PutObjectRequest{
		Bucket:      oss.Ptr(targetBucket),
		Key:         oss.Ptr(objectName),
		Body:        bytes.NewReader(data),
		ContentType: oss.Ptr(utils.GetContentTypeByExt(ext)),
	})
	if err != nil {
		return "", fmt.Errorf("failed to upload bytes to OSS: %w", err)
	}

	return fmt.Sprintf("oss://%s/%s", targetBucket, objectName), nil
}

// CopyFile copies an existing OSS object to a new knowledge-owned object using a
// server-side CopyObject (no data leaves OSS). The destination uses the same
// layout as SaveFile. Returns ErrCrossBackendCopy when srcPath is not an oss:// path.
func (s *ossFileService) CopyFile(ctx context.Context,
	srcPath string, tenantID uint64, knowledgeID string,
) (string, error) {
	srcBucket, srcKey, err := parseOssFilePath(srcPath)
	if err != nil {
		return "", fmt.Errorf("oss copy rejected source %q: %w", srcPath, ErrCrossBackendCopy)
	}
	if err := utils.SafeObjectKey(srcKey); err != nil {
		return "", fmt.Errorf("invalid source path: %w", err)
	}

View on GitHub (pinned to 988cbb0330)