{"record":{"id":"742855864d8d6963","repo":"wavetermdev/waveterm","slug":"invalid-app-name-must-match-pattern-a-za-z0-9","errorCode":null,"errorMessage":"invalid app name: must match pattern [a-zA-Z0-9_-]+","messagePattern":"invalid app name: must match pattern \\[a-zA-Z0-9_-\\]\\+","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":75,"sourceCode":"\treturn appNS, appName, nil\n}\n\nfunc ValidateAppId(appId string) error {\n\tappNS, appName, err := ParseAppId(appId)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(appNS) > MaxNamespaceLen {\n\t\treturn fmt.Errorf(\"namespace too long: max %d characters\", MaxNamespaceLen)\n\t}\n\tif len(appName) > MaxAppNameLen {\n\t\treturn fmt.Errorf(\"app name too long: max %d characters\", MaxAppNameLen)\n\t}\n\tif !namespaceRegex.MatchString(appNS) {\n\t\treturn fmt.Errorf(\"invalid namespace: must match pattern @?[a-z0-9-]+\")\n\t}\n\tif !appNameRegex.MatchString(appName) {\n\t\treturn fmt.Errorf(\"invalid app name: must match pattern [a-zA-Z0-9_-]+\")\n\t}\n\treturn nil\n}\n\nfunc GetAppDir(appId string) (string, error) {\n\tif err := ValidateAppId(appId); err != nil {\n\t\treturn \"\", err\n\t}\n\tappNS, appName, _ := ParseAppId(appId)\n\thomeDir := wavebase.GetHomeDir()\n\treturn filepath.Join(homeDir, \"waveapps\", appNS, appName), nil\n}\n\nfunc copyDir(src, dst string) error {\n\tif err := os.RemoveAll(dst); err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"failed to remove existing directory: %w\", err)\n\t}\n\tif err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L57-L93","documentation":"The app name segment of an appId must match ^[a-zA-Z0-9_-]+$ — only ASCII letters, digits, underscores, and hyphens. This error means the name contains other characters (dots, spaces, slashes, unicode) making it unsafe as a directory name under ~/.waveapps.","triggerScenarios":"Calling ValidateAppId (directly or via GetAppDir, PublishDraft, RevertDraft, MakeDraftFromLocal, DeleteApp, WriteAppFile) with app names like \"my.app\", \"my app\", \"マイアプリ\", or \"app v2\" after the namespace slash.","commonSituations":"Deriving app names from file names or titles that include dots and spaces; localized/unicode app titles used verbatim as ids; version suffixes like \"myapp-1.0\" containing a dot.","solutions":["Sanitize the name: replace '.' and spaces with '-' or '_', and transliterate/strip non-ASCII characters.","Use a slug function before composing the appId (e.g. strings.NewReplacer(\".\", \"-\", \" \", \"-\")).","Pre-validate in UI with pattern ^[a-zA-Z0-9_-]+$ and reject at input time.","Use \"myapp-1-0\" style version suffixes instead of dotted versions."],"exampleFix":"// before\nappId := \"local/myapp-1.0\" // dot not allowed in app name\nerr := waveappstore.ValidateAppId(appId)\n// after\nappId := \"local/myapp-1-0\" // matches ^[a-zA-Z0-9_-]+$\nerr := waveappstore.ValidateAppId(appId)","handlingStrategy":"validation","validationCode":"var appNamePattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)\nfunc namePatternOK(appId string) bool {\n    _, name, err := waveappstore.ParseAppId(appId)\n    return err == nil && appNamePattern.MatchString(name)\n}","typeGuard":"func isValidAppName(name string) bool {\n    return regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString(name)\n}","tryCatchPattern":"if err := waveappstore.ValidateAppId(appId); err != nil {\n    if strings.Contains(err.Error(), \"invalid app name\") {\n        return fmt.Errorf(\"app name may only contain letters, digits, '_' and '-': %w\", err)\n    }\n    return err\n}","preventionTips":["Sanitize derived names: replace dots/spaces with '-' and strip non-ASCII.","Use hyphen version suffixes ('myapp-1-0'), not dotted ones.","Validate the name pattern in UI forms before publishing or writing files.","Test app names copied from file names and titles — the most common source of bad characters."],"tags":["go","validation","regex","naming-convention"],"backgroundTag":"invalid-identifier-format","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}