{"record":{"id":"706fc1395aa80da8","repo":"nsqio/nsq","slug":"invalid-arg-topic","errorCode":"INVALID_ARG_TOPIC","errorMessage":"INVALID_ARG_TOPIC","messagePattern":"INVALID_ARG_TOPIC","errorType":"http","errorClass":"http_api.Err","httpStatus":400,"severity":"error","filePath":"internal/http_api/topic_channel_args.go","lineNumber":20,"sourceCode":"\nimport (\n\t\"errors\"\n\n\t\"github.com/nsqio/nsq/internal/protocol\"\n)\n\ntype getter interface {\n\tGet(key string) (string, error)\n}\n\nfunc GetTopicChannelArgs(rp getter) (string, string, error) {\n\ttopicName, err := rp.Get(\"topic\")\n\tif err != nil {\n\t\treturn \"\", \"\", errors.New(\"MISSING_ARG_TOPIC\")\n\t}\n\n\tif !protocol.IsValidTopicName(topicName) {\n\t\treturn \"\", \"\", errors.New(\"INVALID_ARG_TOPIC\")\n\t}\n\n\tchannelName, err := rp.Get(\"channel\")\n\tif err != nil {\n\t\treturn \"\", \"\", errors.New(\"MISSING_ARG_CHANNEL\")\n\t}\n\n\tif !protocol.IsValidChannelName(channelName) {\n\t\treturn \"\", \"\", errors.New(\"INVALID_ARG_CHANNEL\")\n\t}\n\n\treturn topicName, channelName, nil\n}\n","sourceCodeStart":2,"sourceCodeEnd":34,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/internal/http_api/topic_channel_args.go#L2-L34","documentation":"After the topic parameter is present, GetTopicChannelArgs validates it with protocol.IsValidTopicName, which enforces the regex ^[.a-zA-Z0-9_-]+(#ephemeral)?$ plus a length of 1..64 characters. A value that fails (including an empty string) returns INVALID_ARG_TOPIC and the HTTP handler responds 400.","triggerScenarios":"Passing a topic containing spaces, slashes, unicode, or other characters outside [.a-zA-Z0-9_-], e.g. ?topic=order/events or ?topic=order queue; passing topic= (empty); passing a name longer than 64 characters. Note that topic#ephemeral IS allowed by the regex.","commonSituations":"Deriving topic names from user input, file paths, or free-form event types without sanitizing; splitting a topic on '/' and accidentally keeping the separator; names trimmed to nothing after URL decoding.","solutions":["Use only letters, digits, dot, underscore, hyphen (optionally the #ephemeral suffix) and 1-64 chars, e.g. topic=orders.created","Sanitize generated topic names at the publisher: replace invalid characters with '_' or '-' before the first publish.","If the name came from URL decoding, verify it is non-empty after decode."],"exampleFix":"# before\ncurl -X POST 'http://127.0.0.1:4151/channel/create?topic=order/created&channel=ch'\n# after\ncurl -X POST 'http://127.0.0.1:4151/channel/create?topic=order.created&channel=ch'","handlingStrategy":"validation","validationCode":"var validTopicChannelNameRegex = regexp.MustCompile(`^[.a-zA-Z0-9_-]+(#ephemeral)?$`)\n\nfunc isValidNSQName(name string) bool {\n\treturn len(name) >= 1 && len(name) <= 64 && validTopicChannelNameRegex.MatchString(name)\n}\n\nif !isValidNSQName(topic) {\n\treturn fmt.Errorf(\"invalid topic name %q\", topic)\n}","typeGuard":"func isValidTopicName(name string) bool {\n\treturn len(name) >= 1 && len(name) <= 64 && validTopicChannelNameRegex.MatchString(name)\n}","tryCatchPattern":"if resp.StatusCode == 400 && strings.Contains(string(body), \"INVALID_ARG_TOPIC\") {\n\ttopic = sanitizeNSQName(topic) // replace [^.a-zA-Z0-9_-] with '_' , truncate to 64\n\t// rebuild and retry once\n}","preventionTips":["Sanitize topic names at the publisher before the first message; NSQ has no rename operation.","Add unit tests asserting your topic generator only emits [.a-zA-Z0-9_-] and length <= 64."],"tags":["nsq","http-api","validation","nsqd"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}