{"record":{"id":"0f2e88c48ccca0e9","repo":"vxcontrol/pentagi","slug":"path-must-not-be-empty","errorCode":null,"errorMessage":"path must not be empty","messagePattern":"path must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/resources/resources.go","lineNumber":139,"sourceCode":"\t}\n\terr := os.Remove(BlobPath(dataDir, hash))\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to delete blob %s: %w\", hash, err)\n\t}\n\treturn nil\n}\n\n// SanitizeResourcePath normalises a client-supplied virtual path and ensures it\n// is safe to use:\n//   - trims whitespace\n//   - converts backslashes to forward slashes\n//   - cleans the path (removes .., double slashes, etc.)\n//   - rejects absolute paths, dot-only components, and paths that exceed MaxPathLength\n//   - returns an error for the empty path\nfunc SanitizeResourcePath(p string) (string, error) {\n\ttrimmed := strings.TrimSpace(p)\n\tif trimmed == \"\" {\n\t\treturn \"\", fmt.Errorf(\"path must not be empty\")\n\t}\n\tif len(trimmed) > MaxPathLength {\n\t\treturn \"\", fmt.Errorf(\"path exceeds maximum allowed length of %d characters\", MaxPathLength)\n\t}\n\n\tnormalized := strings.ReplaceAll(trimmed, \"\\\\\", \"/\")\n\tif strings.HasPrefix(normalized, \"/\") {\n\t\treturn \"\", fmt.Errorf(\"path must be relative\")\n\t}\n\tfor _, part := range strings.Split(normalized, \"/\") {\n\t\tif part == \"..\" {\n\t\t\treturn \"\", fmt.Errorf(\"path must not contain parent directory traversal\")\n\t\t}\n\t}\n\tcleaned := path.Clean(\"/\" + normalized)\n\t// Remove the leading \"/\" we added for Clean, making the path relative.\n\trel := strings.TrimPrefix(cleaned, \"/\")\n\tif rel == \"\" || rel == \".\" {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/resources/resources.go#L121-L157","documentation":"SanitizeResourcePath (resources.go:139) normalizes client-supplied virtual paths and rejects the empty string before any other checks. The error 'path must not be empty' means the input, after strings.TrimSpace, had length zero. It guards Resources, SanitizeResourceDir, ZipResources, AddResourceFromFlow and friends from building blob paths from blank names.","triggerScenarios":"Calling SanitizeResourcePath(\"\") or with a whitespace-only string like \"   \", or passing an unset/zero-value variable; callers such as AddResourceFromFlow or collectAndSanitizeResourcePaths forwarding empty optional path fields from API payloads.","commonSituations":"JSON requests omitting an optional 'path' field which arrives as \"\"; database rows with empty path columns; shell scripts passing unquoted empty variables; form submissions where the user left the path input blank.","solutions":["Check the string is non-empty after trimming before calling any resource API","For optional fields, substitute a default path (e.g. \"uploads/file.bin\") or skip the entry and log it","Validate incoming API payloads with a schema (zod/gozod, JSON schema) requiring non-empty path","Trace which caller produced the empty value (Resources, AddResourceFromFlow, etc.) and fix the data source"],"exampleFix":"// before\nsanitized, err := resources.SanitizeResourcePath(req.Path) // req.Path may be \"\"\n// after\np := strings.TrimSpace(req.Path)\nif p == \"\" { return fmt.Errorf(\"resource path required\") }\nsanitized, err := resources.SanitizeResourcePath(p)","handlingStrategy":"validation","validationCode":"func nonEmptyPath(p string) bool { return strings.TrimSpace(p) != \"\" }\n// guard: if !nonEmptyPath(req.Path) { return errors.New(\"path is required\") }","typeGuard":"func hasResourcePath(p *string) bool { return p != nil && strings.TrimSpace(*p) != \"\" }","tryCatchPattern":"sanitized, err := resources.SanitizeResourcePath(p)\nif err != nil {\n    if strings.Contains(err.Error(), \"path must not be empty\") {\n        return fmt.Errorf(\"client error: missing resource path\")\n    }\n    return err\n}","preventionTips":["Trim and check path fields at the API boundary before persisting or forwarding them","Give optional path fields explicit defaults in request schemas","Reject empty path values in DB writes so legacy rows cannot resurface the error","Return a clear 400 response to clients instead of surfacing the internal error"],"tags":["validation","path","input"],"backgroundTag":"empty-path-rejected","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}