{"record":{"id":"f61a159415473e63","repo":"wavetermdev/waveterm","slug":"invalid-destination-path-w","errorCode":null,"errorMessage":"invalid destination path: %w","messagePattern":"invalid destination path: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":395,"sourceCode":"\nfunc RenameAppFile(appId string, fromFileName string, toFileName string) error {\n\tif err := ValidateAppId(appId); err != nil {\n\t\treturn fmt.Errorf(\"invalid appId: %w\", err)\n\t}\n\n\tappDir, err := GetAppDir(appId)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfromPath, err := validateAndResolveFilePath(appDir, fromFileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid source path: %w\", err)\n\t}\n\n\ttoPath, err := validateAndResolveFilePath(appDir, toFileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid destination path: %w\", err)\n\t}\n\n\tif err := os.MkdirAll(filepath.Dir(toPath), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create destination directory: %w\", err)\n\t}\n\n\tif err := os.Rename(fromPath, toPath); err != nil {\n\t\treturn fmt.Errorf(\"failed to rename file: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc FormatGoFile(appId string, fileName string) error {\n\tif err := ValidateAppId(appId); err != nil {\n\t\treturn fmt.Errorf(\"invalid appId: %w\", err)\n\t}\n","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L377-L413","documentation":"RenameAppFile validates the destination file name by resolving it inside the app directory before performing the rename. validateAndResolveFilePath rejects absolute paths, '..' path traversal, and any path that escapes the app directory. The library wraps that failure as \"invalid destination path\" so callers know the destination fileName argument, not the filesystem, is the problem.","triggerScenarios":"Calling RenameAppFile (via RenameAppFileCommand) with a toFileName that is absolute (e.g. \"/etc/passwd\"), contains \"..\" segments (e.g. \"../other/file.go\"), or resolves outside ~/waveapps/<ns>/<app>.","commonSituations":"Users typing a destination path with leading '/' or '..' in a rename prompt; frontend code passing a full path instead of an app-relative name; path separators from Windows pasted into a rename input.","solutions":["Ensure toFileName is a relative path inside the app (e.g. \"subdir/main.go\"), not an absolute path","Strip any leading '/' and resolve/eliminate any '..' components from toFileName before calling","Join the destination with GetAppDir(appId) and confirm it stays within the app directory","Call validateAndResolveFilePath-equivalent logic (filepath.Clean + prefix check) client-side to pre-validate"],"exampleFix":"// before\nRenameAppFile(appId, \"main.go\", \"/tmp/newname.go\")\n// after\nRenameAppFile(appId, \"main.go\", \"src/newname.go\")","handlingStrategy":"validation","validationCode":"func validDestName(name string) bool {\n\tif filepath.IsAbs(name) {\n\t\treturn false\n\t}\n\tclean := filepath.Clean(name)\n\treturn !strings.HasPrefix(clean, \"..\") && !strings.Contains(clean, string(filepath.Separator)+\"..\")\n}\nif !validDestName(toFileName) {\n\treturn errors.New(\"destination must be a relative path inside the app\")\n}","typeGuard":"func isRelativeInApp(appDir, name string) bool {\n\tif filepath.IsAbs(name) { return false }\n\tclean := filepath.Clean(name)\n\tif strings.HasPrefix(clean, \"..\") { return false }\n\tfull, _ := filepath.Abs(filepath.Join(appDir, clean))\n\troot, _ := filepath.Abs(appDir)\n\treturn strings.HasPrefix(full, root+string(filepath.Separator))\n}","tryCatchPattern":"if err := RenameAppFile(appId, from, to); err != nil {\n\tif strings.Contains(err.Error(), \"invalid destination path\") {\n\t\treturn fmt.Errorf(\"bad rename target %q: %w\", to, err)\n\t}\n\treturn err\n}","preventionTips":["Always pass app-relative file names, never absolute paths or user-typed raw paths","Normalize with filepath.Clean and reject '..' segments before calling","Derive destinations from existing file listings rather than free-text input"],"tags":["path-validation","go","input-validation"],"backgroundTag":"invalid-file-path","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}