{"record":{"id":"0a120aa7ff28f92d","repo":"nsqio/nsq","slug":"missing-arg-topic","errorCode":"MISSING_ARG_TOPIC","errorMessage":"MISSING_ARG_TOPIC","messagePattern":"MISSING_ARG_TOPIC","errorType":"http","errorClass":"http_api.Err","httpStatus":400,"severity":"error","filePath":"internal/http_api/topic_channel_args.go","lineNumber":16,"sourceCode":"package http_api\n\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":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/internal/http_api/topic_channel_args.go#L1-L34","documentation":"internal/http_api.GetTopicChannelArgs parses the 'topic' and 'channel' query parameters for every channel-oriented nsqd/nsqlookupd HTTP endpoint (create channel, delete channel, pause, unpause, empty). rp.Get(\"topic\") returns an error when the key is absent, which is reported as MISSING_ARG_TOPIC and the handler responds 400 Bad Request with that string.","triggerScenarios":"Calling any HTTP API that uses GetTopicChannelArgs without a topic parameter, e.g. curl 'http://127.0.0.1:4151/channel/create?channel=ch' or 'http://127.0.0.1:4151/channel/pause?channel=ch'. A value of topic= (present but empty) does NOT trigger this - it fails the later name check instead.","commonSituations":"Hand-built curl requests with a typo in the parameter name (topics=, Topic=); client code that builds query strings with fmt.Sprintf and forgets the topic; proxies or load balancers that strip unknown query parameters.","solutions":["Add the topic query parameter: ?topic=<name>&channel=<name>.","Check spelling and case - the lookup is exactly 'topic' (url.Values.Get is case-sensitive).","URL-encode the value if it contains special characters such as # (ephemeral topics)."],"exampleFix":"# before\ncurl -X POST 'http://127.0.0.1:4151/channel/create?channel=ch'\n# after\ncurl -X POST 'http://127.0.0.1:4151/channel/create?topic=orders&channel=ch'","handlingStrategy":"validation","validationCode":"q := url.Values{}\nif topic == \"\" {\n\treturn errors.New(\"topic query parameter is required\")\n}\nq.Set(\"topic\", topic)\nq.Set(\"channel\", channel)\nreq, _ := http.NewRequest(\"POST\", nsqdURL+\"/channel/create\", strings.NewReader(q.Encode()))\nreq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")","typeGuard":null,"tryCatchPattern":"resp, err := http.DefaultClient.Do(req)\nif err != nil { return err }\nbody, _ := io.ReadAll(resp.Body)\nif resp.StatusCode == 400 && strings.Contains(string(body), \"MISSING_ARG_TOPIC\") {\n\t// caller omitted the parameter: fix request construction, do not retry blindly\n\treturn fmt.Errorf(\"bad request built: %s\", body)\n}","preventionTips":["Always build query strings with net/url Values instead of fmt.Sprintf so parameters cannot be silently dropped.","Wrap channel admin calls in one client function that always sets both topic and channel."],"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"}