{"record":{"id":"8c493938e5bb2178","repo":"wavetermdev/waveterm","slug":"invalid-appid-namespace-and-name-cannot-be-empty","errorCode":null,"errorMessage":"invalid appId: namespace and name cannot be empty","messagePattern":"invalid appId: namespace and name cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveappstore/waveappstore.go","lineNumber":55,"sourceCode":"\ntype FileData struct {\n\tContents []byte\n\tModTs    int64\n}\n\nfunc MakeAppId(appNS string, appName string) string {\n\treturn appNS + \"/\" + appName\n}\n\nfunc ParseAppId(appId string) (appNS string, appName string, err error) {\n\tparts := strings.Split(appId, \"/\")\n\tif len(parts) != 2 {\n\t\treturn \"\", \"\", fmt.Errorf(\"invalid appId format: must be namespace/name\")\n\t}\n\tappNS = parts[0]\n\tappName = parts[1]\n\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}","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveappstore/waveappstore.go#L37-L73","documentation":"ParseAppId accepts exactly two '/'-separated segments but rejects ids where either the namespace or the name segment is empty. This catches malformed ids like \"/myapp\" (missing namespace), \"local/\" (missing name), or \"//\". The segments become directory names under ~/.waveapps, so empty segments would produce invalid paths.","triggerScenarios":"Passing an appId whose namespace or name is the empty string: \"/myapp\", \"local/\", or \"/\"; building ids via string concatenation like ns + \"/\" + name where ns or name is an uninitialized/blank variable.","commonSituations":"An environment variable or config key holding the namespace is unset, so the id starts with '/'; CLI flag parsing yields an empty app name; template/placeholder substitution left a segment blank.","solutions":["Ensure both segments are non-empty: \"local/myapp\", not \"/myapp\" or \"local/\".","Use waveappstore.MakeAppId(ns, name) with validated ns/name inputs rather than manual concatenation.","Log or validate ns and name separately before combining them into an appId.","Call waveappstore.ValidateAppId to catch this together with length/pattern issues."],"exampleFix":"// before\nns := os.Getenv(\"WAVE_APP_NS\") // \"\" if unset\nappId := ns + \"/myapp\"          // \"/myapp\" -> error\n// after\nns := os.Getenv(\"WAVE_APP_NS\")\nif ns == \"\" {\n    ns = waveappstore.AppNSLocal\n}\nappId := waveappstore.MakeAppId(ns, \"myapp\")","handlingStrategy":"validation","validationCode":"ns, name, err := waveappstore.ParseAppId(appId)\nif err == nil && (ns == \"\" || name == \"\") {\n    err = fmt.Errorf(\"namespace and name must be non-empty\")\n}\nif err != nil { /* resolve before calling store APIs */ }","typeGuard":"func hasBothSegments(appId string) bool {\n    parts := strings.Split(appId, \"/\")\n    return len(parts) == 2 && parts[0] != \"\" && parts[1] != \"\"\n}","tryCatchPattern":"if err := waveappstore.ValidateAppId(appId); err != nil {\n    if strings.Contains(err.Error(), \"cannot be empty\") {\n        return fmt.Errorf(\"check that WAVE_APP_NS / app name inputs are set: %w\", err)\n    }\n    return err\n}","preventionTips":["Default the namespace (e.g. to AppNSLocal) when config/env inputs are empty.","Validate ns and name individually before combining them into an id.","Reject blank form/CLI fields at input time with a required-field check.","Watch for template placeholders that silently expand to empty strings."],"tags":["go","validation","identifier-format","waveapp"],"backgroundTag":"invalid-identifier-format","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}