{"record":{"id":"94d22d637d619314","repo":"wavetermdev/waveterm","slug":"draft-app-s-already-exists","errorCode":null,"errorMessage":"draft app '%s' already exists","messagePattern":"draft app '(.+?)' already exists","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":694,"sourceCode":"\tif _, err := os.Stat(oldDraftDir); err == nil {\n\t\tdraftExists = true\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to check draft app: %w\", err)\n\t}\n\n\tif !localExists && !draftExists {\n\t\treturn fmt.Errorf(\"app '%s' does not exist in local or draft namespace\", appName)\n\t}\n\n\t// Check if new app name already exists in either namespace\n\tif _, err := os.Stat(newLocalDir); err == nil {\n\t\treturn fmt.Errorf(\"local app '%s' already exists\", newAppName)\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to check if new local app exists: %w\", err)\n\t}\n\n\tif _, err := os.Stat(newDraftDir); err == nil {\n\t\treturn fmt.Errorf(\"draft app '%s' already exists\", newAppName)\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to check if new draft app exists: %w\", err)\n\t}\n\n\t// Rename local app if it exists\n\tif localExists {\n\t\tif err := os.Rename(oldLocalDir, newLocalDir); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to rename local app: %w\", err)\n\t\t}\n\t}\n\n\t// Rename draft app if it exists\n\tif draftExists {\n\t\tif err := os.Rename(oldDraftDir, newDraftDir); err != nil {\n\t\t\t// If local was renamed but draft fails, try to rollback local rename\n\t\t\tif localExists {\n\t\t\t\tif rollbackErr := os.Rename(newLocalDir, oldLocalDir); rollbackErr != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to rename draft app (and failed to rollback local rename: %v): %w\", rollbackErr, err)","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L676-L712","documentation":"Renames are also blocked if the new name already exists in the draft namespace. When os.Stat(newDraftDir) succeeds, RenameLocalApp returns \"draft app '%s' already exists\" so a local rename cannot silently collide with an in-progress draft of the same name.","triggerScenarios":"Calling RenameLocalApp(oldName, newName) where ~/waveapps/draft/<newName> exists — e.g. a draft with that name was created earlier or a previous draft/publish cycle left the directory behind.","commonSituations":"Renaming to a name that was previously drafted but never published, leftover draft directories after interrupted workflows, or intentional drafts the user forgot about.","solutions":["Choose a newName not present in either the local or draft namespace","Delete the stale draft directory (~/waveapps/draft/<newName>) if it is no longer needed","Publish or clean up the existing draft first, then retry the rename"],"exampleFix":"// before\nRenameLocalApp(\"myapp\", \"wipapp\") // draft:wipapp exists\n// after\nos.RemoveAll(filepath.Join(home, \"waveapps\", \"draft\", \"wipapp\")) // only if stale\nRenameLocalApp(\"myapp\", \"wipapp\")","handlingStrategy":"validation","validationCode":"func draftNameTaken(name string) bool {\n    _, err := os.Stat(filepath.Join(wavebase.GetHomeDir(), \"waveapps\", \"draft\", name))\n    return err == nil\n}\n// require !draftNameTaken(newName) before renaming","typeGuard":null,"tryCatchPattern":"if err := waveappstore.RenameLocalApp(oldName, newName); err != nil {\n    if strings.Contains(err.Error(), \"draft app\") && strings.Contains(err.Error(), \"already exists\") {\n        // prompt user to resolve/remove the draft or pick another name\n        return fmt.Errorf(\"a draft named %q exists; resolve it first\", newName)\n    }\n    return err\n}","preventionTips":["Check both local and draft namespaces for the target name before renaming","Clean up stale drafts after failed publish workflows","Prefix ad-hoc draft names so they are easy to identify and prune"],"tags":["go","rename","conflict","draft","waveappstore"],"backgroundTag":"name-already-exists","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}