{"record":{"id":"9707d08ed924539c","repo":"apache/beam","slug":"received-message-missing-ackid-pubsubjsonclient","errorCode":null,"errorMessage":"Received message missing ackId","messagePattern":"Received message missing ackId","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubJsonClient.java","lineNumber":215,"sourceCode":"      String dataStr = pubsubMessage.getData();\n      byte[] elementBytes = (dataStr == null) ? new byte[0] : pubsubMessage.decodeData();\n\n      // Timestamp.\n      long timestampMsSinceEpoch;\n      if (timestampAttribute == null || timestampAttribute.isEmpty()) {\n        String publishTime = pubsubMessage.getPublishTime();\n        if (publishTime == null) {\n          throw new IllegalStateException(\"Received message missing publishTime\");\n        }\n        timestampMsSinceEpoch = parseTimestampAsMsSinceEpoch(publishTime);\n      } else {\n        timestampMsSinceEpoch = extractTimestampAttribute(timestampAttribute, attributes);\n      }\n\n      // Ack id.\n      String ackId = message.getAckId();\n      if (ackId == null || ackId.isEmpty()) {\n        throw new IllegalStateException(\"Received message missing ackId\");\n      }\n\n      // Record id, if any.\n      @Nullable String recordId = null;\n      if (idAttribute != null) {\n        recordId = attributes.get(idAttribute);\n      }\n      if (recordId == null || recordId.isEmpty()) {\n        // Fall back to the Pubsub provided message id.\n        recordId = checkStateNotNull(pubsubMessage.getMessageId(), \"Message ID is missing\");\n      }\n\n      com.google.pubsub.v1.PubsubMessage.Builder protoMessage =\n          com.google.pubsub.v1.PubsubMessage.newBuilder();\n      protoMessage.setData(ByteString.copyFrom(elementBytes));\n      protoMessage.putAllAttributes(attributes);\n      // {@link PubsubMessage} uses `null` or empty string to represent no ordering key.\n      // {@link com.google.pubsub.v1.PubsubMessage} does not track string field presence and uses","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubJsonClient.java#L197-L233","documentation":"PubsubJsonClient.pull() requires each message in the pull response to carry an ackId used for later acknowledgment. If message.getAckId() is null or empty, IllegalStateException \"Received message missing ackId\" is thrown. Like the missing publishTime error, this signals a malformed response from the Pub/Sub backend.","triggerScenarios":"pull() returning a message entry without an ackId — typically from a non-conformant emulator/proxy response, truncated API responses, or a hand-rolled fake Pub/Sub service used in tests.","commonSituations":"Custom Pub/Sub emulators in CI, MITM proxies rewriting responses, or newer API client versions interacting badly with the response parser.","solutions":["Fix or replace the emulator/proxy so pull responses include ackId for every message.","Use the official Google Pub/Sub emulator, which always returns ackId.","Verify the Google API client and Beam SDK versions are compatible.","Inspect the raw JSON response to confirm which entries are missing ackId."],"exampleFix":"// before (fake emulator response)\n{\"receivedMessages\": [{\"message\": {\"data\": \"...\"}}]}\n// after\n{\"receivedMessages\": [{\"ackId\": \"ack-1\", \"message\": {\"data\": \"...\"}}]}","handlingStrategy":"validation","validationCode":"for (ReceivedMessage m : response.getReceivedMessagesOrDefault(new ArrayList<>())) {\n  if (m.getAckId() == null || m.getAckId().isEmpty()) {\n    throw new IllegalStateException(\"Response entry missing ackId; backend is non-conformant\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  incoming = client.pull(request);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"missing ackId\")) {\n    // treat backend as broken: reconnect or switch to the official emulator\n  }\n}","preventionTips":["Use the official Google Pub/Sub emulator or the real service in tests, not hand-rolled fakes.","Assert pull-response shape in CI integration tests.","Avoid proxies that rewrite Pub/Sub API responses."],"tags":["java","pubsub","gcp","api-response","internal"],"backgroundTag":"unexpected-response-shape","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}