{"record":{"id":"ccf867b1ab665ddc","repo":"Tencent/WeKnora","slug":"invalid-file-name-w-ccf867","errorCode":null,"errorMessage":"invalid file name: %w","messagePattern":"invalid file name: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/file/oss.go","lineNumber":223,"sourceCode":"\t\t\tKey:         oss.Ptr(objectName),\n\t\t\tBody:        src,\n\t\t\tContentType: oss.Ptr(contentType),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to upload file to OSS: %w\", err)\n\t\t}\n\t}\n\n\treturn fmt.Sprintf(\"oss://%s/%s\", s.bucketName, objectName), nil\n}\n\n// SaveBytes saves bytes data to OSS.\n// If temp is true and temp bucket is configured, saves to temp bucket.\n// Otherwise saves to main bucket.\nfunc (s *ossFileService) SaveBytes(ctx context.Context, data []byte, tenantID uint64, fileName string, temp bool) (string, error) {\n\tsafeName, err := utils.SafeFileName(fileName)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid file name: %w\", err)\n\t}\n\text := filepath.Ext(safeName)\n\n\ttargetBucket := s.bucketName\n\tclient := s.client\n\tobjectName := fmt.Sprintf(\"%s%d/exports/%s%s\", s.pathPrefix, tenantID, uuid.New().String(), ext)\n\n\tif temp && s.tempClient != nil {\n\t\ttargetBucket = s.tempBucketName\n\t\tclient = s.tempClient\n\t\tobjectName = fmt.Sprintf(\"exports/%d/%s%s\", tenantID, uuid.New().String(), ext)\n\t}\n\n\t_, err = client.PutObject(ctx, &oss.PutObjectRequest{\n\t\tBucket:      oss.Ptr(targetBucket),\n\t\tKey:         oss.Ptr(objectName),\n\t\tBody:        bytes.NewReader(data),\n\t\tContentType: oss.Ptr(utils.GetContentTypeByExt(ext)),","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/file/oss.go#L205-L241","documentation":"This error is returned by ossFileService.SaveBytes when utils.SafeFileName rejects the supplied fileName. SafeFileName sanitizes/validates user-provided names (strips path components, disallowed characters, empty names) and returns an error when the name cannot be made safe. The service wraps that error so callers know the failure was in name validation, not the OSS upload.","triggerScenarios":"Calling SaveBytes with a fileName that is empty, contains path separators or traversal sequences (../), illegal characters (control chars, reserved names), or is otherwise rejected by utils.SafeFileName.","commonSituations":"Export pipelines passing raw user-uploaded filenames straight to SaveBytes; filenames containing Windows-reserved names or unicode oddities; empty fileName when the caller never set the original document name.","solutions":["Log/inspect the wrapped error from SafeFileName to see which rule failed.","Sanitize the filename on the caller side before calling SaveBytes (strip directories, allow alphanumerics/-/_/.).","Fall back to a generated default name when the original is invalid (the service already appends a UUID, so the name only matters for the extension).","Add upstream validation at the API/ingest layer so bad names never reach the storage layer."],"exampleFix":"// before\nerr := svc.SaveBytes(ctx, data, tenantID, rawUserFileName, false)\n// after\nsafe, err := utils.SafeFileName(rawUserFileName)\nif err != nil {\n    safe = \"export\" + filepath.Ext(rawUserFileName)\n}\nerr = svc.SaveBytes(ctx, data, tenantID, safe, false)","handlingStrategy":"validation","validationCode":"func validFileName(name string) bool {\n    if name == \"\" || len(name) > 255 { return false }\n    if strings.ContainsAny(name, \"/\\\\\\x00\") { return false }\n    if strings.Contains(name, \"..\") { return false }\n    return true\n}\n// call before SaveBytes\nif !validFileName(fileName) { return errors.New(\"reject bad file name\") }","typeGuard":null,"tryCatchPattern":"if err := saveBytes(...); err != nil {\n    if strings.Contains(err.Error(), \"invalid file name\") {\n        // fall back to generated name or reject input\n    }\n}","preventionTips":["Sanitize filenames at the API/ingest boundary, not at storage time.","Never trust client-supplied names: strip directory components and control characters.","Keep only the extension from user names; generate the object name server-side.","Add unit tests for SafeFileName with traversal, unicode, and reserved-name cases."],"tags":["oss","validation","filename","sanitization"],"backgroundTag":"invalid-filename","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}