{"record":{"id":"b466079baa4b1e90","repo":"nestjs/nest","slug":"an-unsupported-message-was-received-it-has-been-n","errorCode":null,"errorMessage":"An unsupported message was received. It has been negative acknowledged, so it will not be re-delivered. Pattern: ${pattern}","messagePattern":"An unsupported message was received\\. It has been negative acknowledged, so it will not be re-delivered\\. Pattern: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/microservices/server/server-rmq.ts","lineNumber":313,"sourceCode":"    if (isNil(message)) {\n      return;\n    }\n    const { content, properties } = message;\n    const rawMessage = this.parseMessageContent(content);\n    const packet = await this.deserializer.deserialize(rawMessage, properties);\n    const pattern = isString(packet.pattern)\n      ? packet.pattern\n      : JSON.stringify(packet.pattern);\n\n    const rmqContext = new RmqContext([message, channel, pattern]);\n    if (isUndefined((packet as IncomingRequest).id)) {\n      return this.handleEvent(pattern, packet, rmqContext);\n    }\n    const handler = this.getHandlerByPattern(pattern);\n\n    if (!handler) {\n      if (!this.noAck) {\n        this.logger.warn(RMQ_NO_MESSAGE_HANDLER`${pattern}`);\n        this.channel!.nack(rmqContext.getMessage() as Message, false, false);\n      }\n      const status = 'error';\n      const noHandlerPacket = {\n        id: (packet as IncomingRequest).id,\n        err: NO_MESSAGE_HANDLER,\n        status,\n      };\n      return this.sendMessage(\n        noHandlerPacket,\n        properties.replyTo,\n        properties.correlationId,\n        rmqContext,\n      );\n    }\n    return this.onProcessingStartHook(\n      this.transportId,\n      rmqContext,","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/nestjs/nest/blob/dd75d7bd8c5e88048587e6768d36eb695f3e7a25/packages/microservices/server/server-rmq.ts#L295-L331","documentation":"ServerRMQ received an incoming request (a packet with an `id`, i.e. one expecting a reply) whose serialized pattern matches no registered @MessageHandler (getHandlerByPattern returned undefined). In manual-ack mode (noAck false, the default) the server negative-acknowledges the message with requeue=false — RabbitMQ drops it permanently — and logs this warning; the requesting client instead receives an error response carrying the constant NO_MESSAGE_HANDLER ('There is no matching message handler defined in the remote service.'). With noAck: true the nack and warning are skipped but the drop is equally silent.","triggerScenarios":"client.send(pattern, payload) where the pattern does not exactly equal a @MessageHandler(pattern) on the server: typos, casing differences, or object patterns whose JSON.stringify key order differs (matching uses the serialized string). Also raw JSON published to the service's queue by external producers lacking the {id, pattern, data} contract, and version skew where a new producer ships before the consumer that handles the new pattern.","commonSituations":"Pattern typos between services; renaming a handler while old messages sit in the queue; multiple microservices configured with the same queue so messages round-robin to an instance that never registered the pattern; rolling deploys with old and new pattern names; third-party systems publishing directly to the queue.","solutions":["Make the pattern identical on both sides — exact string, or a shared object constant — and remember object patterns are matched by their JSON serialization, so key order matters.","Give each microservice its own queue; a shared queue round-robins messages to instances that may not have the handler.","Confirm the module containing the handlers is actually imported before producers go live (inspect registered patterns at startup).","Configure a dead-letter exchange on the queue so nacked unsupported messages are captured for inspection instead of silently dropped, and purge stale messages after renaming/removing patterns.","During rolling deploys, ship the consumer that handles both old and new patterns before switching producers."],"exampleFix":"// before\n// producer\nthis.client.send({ cmd: 'get-user' }, id);\n// consumer\n@MessageHandler({ cmd: 'get_user' }) // mismatch -> nack, message dropped\n\n// after: one shared constant (shared package)\nexport const GET_USER = { cmd: 'get-user' } as const;\n// producer\nthis.client.send(GET_USER, id);\n// consumer\n@MessageHandler(GET_USER)\ngetUser(@Payload() id: string) { /* ... */ }","handlingStrategy":"validation","validationCode":"// share one source of truth for patterns and validate before publishing\nexport const PATTERNS = ['users.get', 'users.create'] as const;\nexport type Pattern = (typeof PATTERNS)[number];\n\nfunction assertKnownPattern(p: string): asserts p is Pattern {\n  if (!(PATTERNS as readonly string[]).includes(p)) {\n    throw new Error(`Unknown pattern '${p}': server has no @MessageHandler for it`);\n  }\n}\n\nassertKnownPattern(pattern);\nthis.client.send(pattern, payload);","typeGuard":"const PATTERNS = ['users.get', 'users.create'] as const;\ntype Pattern = (typeof PATTERNS)[number];\nconst isPattern = (p: string): p is Pattern =>\n  (PATTERNS as readonly string[]).includes(p);","tryCatchPattern":"this.client.send<string, User>(pattern, payload).subscribe({\n  next: (user) => this.logger.log(user),\n  error: (err) => {\n    // server replied with the NO_MESSAGE_HANDLER constant\n    if (/no matching message handler/i.test(String(err?.message ?? err))) {\n      // pattern contract is broken: alert and stop retrying, this is not transient\n    }\n  },\n});","preventionTips":["Export pattern constants from a shared package instead of retyping strings per service","Use a dedicated queue per microservice; never share queues between services with different handlers","Configure a dead-letter exchange so nacked unsupported messages are captured, and monitor it","Run contract/e2e tests covering every published pattern against the consumer before deploy","Deploy the consumer before the producer when introducing new patterns; purge queues when renaming patterns"],"tags":["rabbitmq","amqp","message-routing","pattern-mismatch","nack","dead-letter"],"backgroundTag":"message-pattern-no-handler","analyzedSha":"dd75d7bd8c5e88048587e6768d36eb695f3e7a25","analyzedAt":"2026-08-21T19:39:39.867Z","contentChangedAt":"2026-08-21T19:39:39.867Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}