{"record":{"id":"c726fb3bd343e588","repo":"nsqio/nsq","slug":"e-mpub-failed","errorCode":"E_MPUB_FAILED","errorMessage":"exiting","messagePattern":"exiting","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nsqd/topic.go","lineNumber":203,"sourceCode":"\tdefer t.RUnlock()\n\tif atomic.LoadInt32(&t.exitFlag) == 1 {\n\t\treturn errors.New(\"exiting\")\n\t}\n\terr := t.put(m)\n\tif err != nil {\n\t\treturn err\n\t}\n\tatomic.AddUint64(&t.messageCount, 1)\n\tatomic.AddUint64(&t.messageBytes, uint64(len(m.Body)))\n\treturn nil\n}\n\n// PutMessages writes multiple Messages to the queue\nfunc (t *Topic) PutMessages(msgs []*Message) error {\n\tt.RLock()\n\tdefer t.RUnlock()\n\tif atomic.LoadInt32(&t.exitFlag) == 1 {\n\t\treturn errors.New(\"exiting\")\n\t}\n\n\tmessageTotalBytes := 0\n\n\tfor i, m := range msgs {\n\t\terr := t.put(m)\n\t\tif err != nil {\n\t\t\tatomic.AddUint64(&t.messageCount, uint64(i))\n\t\t\tatomic.AddUint64(&t.messageBytes, uint64(messageTotalBytes))\n\t\t\treturn err\n\t\t}\n\t\tmessageTotalBytes += len(m.Body)\n\t}\n\n\tatomic.AddUint64(&t.messageBytes, uint64(messageTotalBytes))\n\tatomic.AddUint64(&t.messageCount, uint64(len(msgs)))\n\treturn nil\n}","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/nsqd/topic.go#L185-L221","documentation":"Topic.PutMessages (nsqd/topic.go) is the batched write path used by the MPUB and MPUB cl commands. Like PutMessage it refuses work when the topic's exitFlag is set (topic deleting or nsqd shutting down) and returns 'exiting'; the protocol layer maps that to E_MPUB_FAILED for the client. If a later message in the loop fails, only the successfully written prefix is credited to messageCount/messageBytes — the guard and the accounting both exist because MPUB is not transactional.","triggerScenarios":"An MPUB (or internal PutMessages) racing topic deletion or nsqd shutdown: exitFlag is observed as 1 before any message is written and the whole batch is rejected with E_MPUB_FAILED. Also triggered when batch writes straddle shutdown: some messages land, then the error surfaces after the partial counters are updated.","commonSituations":"Consumers using ephemeral topics that auto-delete when their channels drain while a producer MPUBs; deployment scripts killing nsqd before producers drain; burst publishing during rolling restarts; test harnesses tearing down nsqd immediately after publishing.","solutions":["Retry the batch after the producer reconnects and the topic exists again (go-nsq Producer.Publish of multiple messages / MPUB handles reconnect internally).","For ephemeral topics, keep at least one non-ephemeral channel so the topic is not deleted under your producer.","Drain or stop producers before deleting topics or stopping nsqd when you need the last batches accepted.","Treat E_MPUB_FAILED as non-permanent for this condition: log, back off briefly, re-resolve the topic, resend."],"exampleFix":"# before: fire-and-forget MPUB during restarts\n$ nsq_pub -topic alerts -multimsg msgs.txt  # may fail with E_MPUB_FAILED (exiting)\n\n# after: retry once after reconnect/re-resolve\nfor i in 1 2; do\n  nsq_pub -topic alerts -multimsg msgs.txt && break\n  sleep 1   # let nsqd restart / topic recreate, then retry the whole batch\n  nsq_pub -topic alerts -create-topic >/dev/null\n  done","handlingStrategy":"retry","validationCode":"// with go-nsq, verify the producer is connected and the topic exists before MPUB\nif p := nsqProducer; !p.Ping() {\n    // go-nsq reconnects internally; wait or fail fast before batching\n    return errors.New(\"producer not connected; deferring MPUB\")\n}","typeGuard":null,"tryCatchPattern":"// treat E_MPUB_FAILED / exiting as transient: back off and resend the batch\nif err := producer.MultiPublish(msgs); err != nil {\n    if strings.Contains(err.Error(), \"E_MPUB_FAILED\") || strings.Contains(err.Error(), \"exiting\") {\n        time.Sleep(backoff)\n        err = producer.MultiPublish(msgs) // idempotent consumers recommended\n    }\n    return err\n}","preventionTips":["Design MPUB consumers idempotent so whole-batch retries are safe.","Keep durable channels on topics you MPUB to, preventing ephemeral auto-delete races.","Coordinate shutdown order: stop publishers before nsqd in orchestration."],"tags":["lifecycle","shutdown","mpub","topic","concurrency","nsqd"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}