{"record":{"id":"0c25807b61949c9d","repo":"caddyserver/caddy","slug":"module-name-is-required","errorCode":null,"errorMessage":"module name is required","messagePattern":"module name is required","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/packagesfuncs.go","lineNumber":62,"sourceCode":"\t}\n\n\treturn upgradeBuild(pluginPkgs, fl)\n}\n\nfunc splitModule(arg string) (module, version string, err error) {\n\tconst versionSplit = \"@\"\n\n\t// accommodate module paths that have @ in them, but we can only tolerate that if there's also\n\t// a version, otherwise we don't know if it's a version separator or part of the file path\n\tlastVersionSplit := strings.LastIndex(arg, versionSplit)\n\tif lastVersionSplit < 0 {\n\t\tmodule = arg\n\t} else {\n\t\tmodule, version = arg[:lastVersionSplit], arg[lastVersionSplit+1:]\n\t}\n\n\tif module == \"\" {\n\t\terr = fmt.Errorf(\"module name is required\")\n\t}\n\n\treturn module, version, err\n}\n\nfunc cmdAddPackage(fl Flags) (int, error) {\n\tif len(fl.Args()) == 0 {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"at least one package name must be specified\")\n\t}\n\t_, nonstandard, _, err := getModules()\n\tif err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"unable to enumerate installed plugins: %v\", err)\n\t}\n\tpluginPkgs, err := getPluginPackages(nonstandard)\n\tif err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, err\n\t}\n","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/cmd/packagesfuncs.go#L44-L80","documentation":"splitModule rejects a module argument whose module-path portion is empty. Arguments are split at the LAST '@': everything before is the module path, everything after the version. If nothing precedes the '@', there is no module name to install or remove.","triggerScenarios":"Passing `@v1.2.3` or just `@` to `caddy add-package` / `caddy remove-package`. Also `foo@@v1.2.3`-style typos are fine for the split, but a leading '@' always yields an empty module.","commonSituations":"Shell quoting mistakes that drop the module path (e.g. `$pkg@v1` with pkg unset → `@v1`), copy-paste from docs that mangled the module path, or tab-completion inserting the version separator first.","solutions":["Supply the full module path: `caddy add-package github.com/caddy-dns/cloudflare`","Include the version only after a complete path: `github.com/caddy-dns/cloudflare@v0.2.1`","Check shell variables are set before using them in the package argument"],"exampleFix":"# before\ncaddy add-package @v0.2.1\n\n# after\ncaddy add-package github.com/caddy-dns/cloudflare@v0.2.1","handlingStrategy":"validation","validationCode":"valid_module() { [[ \"$1\" =~ ^[^@[:space:]]+(@[^[:space:]]+)?$ ]]; }\nvalid_module 'github.com/caddy-dns/cloudflare@v0.2.1' || echo 'bad module arg'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass full Go module paths","Check shell variables are non-empty before interpolating into package args"],"tags":["caddy","cli","packages","argument-validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}