{"record":{"id":"e6be463a4fe90c19","repo":"wavetermdev/waveterm","slug":"failed-to-check-draft-app-w","errorCode":null,"errorMessage":"failed to check draft app: %w","messagePattern":"failed to check draft app: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":679,"sourceCode":"\n\toldLocalDir := filepath.Join(waveappsDir, AppNSLocal, appName)\n\tnewLocalDir := filepath.Join(waveappsDir, AppNSLocal, newAppName)\n\toldDraftDir := filepath.Join(waveappsDir, AppNSDraft, appName)\n\tnewDraftDir := filepath.Join(waveappsDir, AppNSDraft, newAppName)\n\n\t// Check if at least one of the apps exists\n\tlocalExists := false\n\tdraftExists := false\n\tif _, err := os.Stat(oldLocalDir); err == nil {\n\t\tlocalExists = true\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to check local app: %w\", err)\n\t}\n\n\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}","sourceCodeStart":661,"sourceCodeEnd":697,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L661-L697","documentation":"Same check as the local variant, but for the old draft directory. If os.Stat(oldDraftDir) fails with anything other than NotExist, RenameLocalApp returns \"failed to check draft app: %w\" so transient/permission errors are not misread as 'app does not exist'.","triggerScenarios":"os.Stat(oldDraftDir) returns a non-ENOENT error: unreadable draft directory, permission denied on parents, or I/O failure.","commonSituations":"Permission changes under ~/waveapps/draft, draft directory owned by another user, disk errors or a read-only filesystem after a crash.","solutions":["Check and fix permissions on ~/waveapps/draft and its contents","Confirm the filesystem is writable/mounted and the disk is healthy","Remount or restart if the filesystem is in a bad state"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"draftDir := filepath.Join(wavebase.GetHomeDir(), \"waveapps\", \"draft\")\nif err := os.Access(draftDir, os.R_OK); err != nil {\n    return fmt.Errorf(\"no read access to draft dir: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := waveappstore.RenameLocalApp(oldName, newName); err != nil {\n    if strings.Contains(err.Error(), \"failed to check draft app\") {\n        // surface as an environment/permissions problem, not 'app missing'\n        return fmt.Errorf(\"cannot read draft dir: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep ~/waveapps/draft readable/writable by the app user","Watch for read-only remounts after crashes and remount rw","Avoid changing ownership of the waveapps tree out from under the process"],"tags":["go","filesystem","permissions","os-stat"],"backgroundTag":"filesystem-permission-denied","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}