{"record":{"id":"27b334cc6465cb45","repo":"wavetermdev/waveterm","slug":"invalid-namespace-must-match-pattern-a-z0-9","errorCode":null,"errorMessage":"invalid namespace: must match pattern @?[a-z0-9-]+","messagePattern":"invalid namespace: must match pattern @\\?\\[a-z0-9-\\]\\+","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":72,"sourceCode":"\tif appNS == \"\" || appName == \"\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"invalid appId: namespace and name cannot be empty\")\n\t}\n\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) {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L54-L90","documentation":"The namespace segment of an appId must match ^@?[a-z0-9-]+$ — optionally starting with '@', then only lowercase letters, digits, and hyphens. This error means the namespace contains other characters (uppercase, underscores, dots, spaces, slashes) or is otherwise malformed.","triggerScenarios":"Calling ValidateAppId (directly or via GetAppDir, PublishDraft, RevertDraft, MakeDraftFromLocal, DeleteApp, WriteAppFile) with namespaces like \"MyOrg/app\", \"my_org/app\", \"my.org/app\", \"@Team/app\", or \"my org/app\".","commonSituations":"Using a GitHub org, npm scope, or domain as the namespace without normalizing case/punctuation ('@MyOrg', 'example.com'); users typing underscores where hyphens are required; copy-pasting ids with spaces or uppercase.","solutions":["Normalize the namespace to lowercase and replace '_'/'.' and other characters with '-'.","Keep the optional '@' prefix only at position 0 (reserved for team/organization namespaces).","Pre-validate in UI with the pattern ^@?[a-z0-9-]+$ and show a clear message.","Migrate any existing app directories stored under non-conforming namespaces to compliant names."],"exampleFix":"// before\nappId := \"@MyOrg_App/myapp\" // uppercase and underscore -> invalid namespace\nerr := waveappstore.ValidateAppId(appId)\n// after\nappId := \"@myorg-app/myapp\" // matches ^@?[a-z0-9-]+$\nerr := waveappstore.ValidateAppId(appId)","handlingStrategy":"validation","validationCode":"var namespacePattern = regexp.MustCompile(`^@?[a-z0-9-]+$`)\nfunc nsPatternOK(appId string) bool {\n    ns, _, err := waveappstore.ParseAppId(appId)\n    return err == nil && namespacePattern.MatchString(ns)\n}","typeGuard":"func isValidNamespace(ns string) bool {\n    return regexp.MustCompile(`^@?[a-z0-9-]+$`).MatchString(ns)\n}","tryCatchPattern":"if err := waveappstore.ValidateAppId(appId); err != nil {\n    if strings.Contains(err.Error(), \"invalid namespace\") {\n        return fmt.Errorf(\"namespace may only contain lowercase letters, digits, and hyphens (optional leading '@'): %w\", err)\n    }\n    return err\n}","preventionTips":["Lowercase and hyphen-normalize org/domain inputs before composing namespaces.","Only allow '@' as the first character; never inside the namespace.","Validate with the pattern at every input boundary (CLI flags, forms, manifests).","Migrate existing directories stored under non-conforming namespace names."],"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-08T10:18:20.063Z"}