{"record":{"id":"855f340c10c824f9","repo":"Tencent/WeKnora","slug":"resource-registration-requires-tenant-and-physical","errorCode":null,"errorMessage":"resource registration requires tenant and physical path","messagePattern":"resource registration requires tenant and physical path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/resource.go","lineNumber":53,"sourceCode":"\t\treturn \"\", err\n\t}\n\treturn base64.RawURLEncoding.EncodeToString(buf), nil\n}\n\nfunc resourceLocationHash(path string) string {\n\tsum := sha256.Sum256([]byte(path))\n\treturn hex.EncodeToString(sum[:])\n}\n\nfunc (s *resourceCatalog) Register(\n\tctx context.Context,\n\ttenantID uint64,\n\tphysicalPath string,\n\tmeta interfaces.ResourceRegistration,\n) (string, error) {\n\tphysicalPath = strings.TrimSpace(physicalPath)\n\tif tenantID == 0 || physicalPath == \"\" {\n\t\treturn \"\", fmt.Errorf(\"resource registration requires tenant and physical path\")\n\t}\n\tif _, ok := types.ParseResourcePath(physicalPath); ok {\n\t\treturn physicalPath, nil\n\t}\n\tlocationHash := resourceLocationHash(physicalPath)\n\texisting, err := s.repo.GetByTenantLocation(ctx, tenantID, locationHash)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif existing != nil {\n\t\treturn types.BuildResourcePath(existing.Handle), nil\n\t}\n\n\tbackendID, inner, scoped := types.ParseStorageBackendPath(physicalPath)\n\tproviderPath := physicalPath\n\tif scoped {\n\t\tproviderPath = inner\n\t}","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/resource.go#L35-L71","documentation":"Resource.Register requires a non-zero tenant ID and a non-empty physical path. After trimming whitespace, if either is missing the registration is rejected outright. This is an input-contract error: nothing can be registered without knowing who owns it and where the bytes live.","triggerScenarios":"Calling Register(ctx, 0, \"\", meta) or with a physicalPath that is only whitespace; programmatically building registrations where tenant scoping was lost upstream (unauthenticated context, nil tenant).","commonSituations":"Upload pipeline losing tenant context before resource registration; passing a file path variable that was never assigned; migrating code that previously registered tenant-less global resources.","solutions":["Ensure the caller has an authenticated context and pass the real tenant ID (non-zero).","Trim and validate physicalPath at the call site before invoking Register.","Fix upstream code that drops the tenant ID (e.g. background jobs losing context values).","Reject earlier in your own API layer with a clearer validation message including which field is missing."],"exampleFix":"// before\nid, err := svc.Register(ctx, tenantID, filePath, meta) // tenantID==0, filePath==\"\"\n// after\nif tenantID == 0 || strings.TrimSpace(filePath) == \"\" {\n    return nil, fmt.Errorf(\"cannot register resource: tenantID=%d path=%q\", tenantID, filePath)\n}\nid, err := svc.Register(ctx, tenantID, strings.TrimSpace(filePath), meta)","handlingStrategy":"validation","validationCode":"if tenantID == 0 { return fmt.Errorf(\"tenantID required\") }\nif strings.TrimSpace(physicalPath) == \"\" { return fmt.Errorf(\"physicalPath required\") }","typeGuard":"func registrable(tenantID uint64, physicalPath string) bool {\n    return tenantID != 0 && strings.TrimSpace(physicalPath) != \"\"\n}","tryCatchPattern":"id, err := svc.Register(ctx, tenantID, path, meta)\nif err != nil && strings.Contains(err.Error(), \"requires tenant and physical path\") {\n    return nil, fmt.Errorf(\"invalid resource registration input: %w\", err)\n}","preventionTips":["Propagate tenant ID through context in background jobs","Validate registration inputs at your API boundary","Never register resources outside an authenticated tenant scope"],"tags":["validation","resource","tenant"],"backgroundTag":"missing-required-argument","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}