{"record":{"id":"74d5e73ff8411fa7","repo":"apache/beam","slug":"pubsub-message-must-contain-a-non-empty-payload-or-at-least","errorCode":null,"errorMessage":"Pubsub message must contain a non-empty payload or at least one attribute.","messagePattern":"Pubsub message must contain a non-empty payload or at least one attribute\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PreparePubsubWriteDoFn.java","lineNumber":92,"sourceCode":"    int totalSize = payloadSize;\n\n    @Nullable String orderingKey = message.getOrderingKey();\n    if (orderingKey != null) {\n      int orderingKeySize = orderingKey.getBytes(StandardCharsets.UTF_8).length;\n      if (orderingKeySize > ORDERING_KEY_MAX_BYTE_SIZE) {\n        throw new SizeLimitExceededException(\n            \"Pubsub message ordering key of length \"\n                + orderingKeySize\n                + \" exceeds maximum of \"\n                + ORDERING_KEY_MAX_BYTE_SIZE\n                + \" bytes. See https://cloud.google.com/pubsub/quotas#resource_limits\");\n      }\n      totalSize += orderingKeySize;\n    }\n\n    final @Nullable Map<String, String> attributes = message.getAttributeMap();\n    if (payloadSize == 0 && (attributes == null || attributes.isEmpty())) {\n      throw new IllegalArgumentException(\n          \"Pubsub message must contain a non-empty payload or at least one attribute.\");\n    }\n\n    if (attributes != null) {\n      if (attributes.size() > PUBSUB_MESSAGE_MAX_ATTRIBUTES) {\n        throw new SizeLimitExceededException(\n            \"Pubsub message contains \"\n                + attributes.size()\n                + \" attributes which exceeds the maximum of \"\n                + PUBSUB_MESSAGE_MAX_ATTRIBUTES\n                + \". See https://cloud.google.com/pubsub/quotas#resource_limits\");\n      }\n\n      // Consider attribute encoding overhead, so it doesn't go over the request limits\n      totalSize += attributes.size() * PUBSUB_MESSAGE_ATTRIBUTE_ENCODE_ADDITIONAL_BYTES;\n\n      for (Map.Entry<String, String> attribute : attributes.entrySet()) {\n        String key = attribute.getKey();","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PreparePubsubWriteDoFn.java#L74-L110","documentation":"Pub/Sub requires every message to carry either non-empty data or at least one attribute; validatePubsubMessage throws IllegalArgumentException when both payload size is 0 and the attribute map is null/empty. This is an early client-side validation of a Pub/Sub API constraint.","triggerScenarios":"Calling validatePubsubMessage (via PreparePubsubWriteDoFn.process) with a PubsubMessage constructed from an empty byte[] payload and no attributes — e.g. an empty record or a failed serialization producing zero bytes.","commonSituations":"Downstream DoFn emitting new PubsubMessage(new byte[0], null); a transformer dropping all fields; encoding logic returning empty arrays for null input; deliberately sending 'tombstone' messages without payload and forgetting attributes.","solutions":["Ensure every message has a non-empty payload or set at least one attribute (e.g. event type)","Add a guard at message-construction time to reject empty payload+attribute combos","If tombstones are intended, put a marker attribute like {\"deleted\":\"true\"}","Fix upstream serialization so null/empty values don't produce zero-length payloads"],"exampleFix":"// before\nnew PubsubMessage(new byte[0], null);\n// after\nMap<String, String> attrs = attrs != null ? attrs : new HashMap<>();\nattrs.putIfAbsent(\"event-type\", \"tombstone\");\nnew PubsubMessage(payload == null ? new byte[0] : payload, attrs);","handlingStrategy":"validation","validationCode":"java\nif ((payload == null || payload.length == 0)\n    && (attrs == null || attrs.isEmpty())) {\n  throw new IllegalArgumentException(\"PubsubMessage needs non-empty payload or at least one attribute\");\n}","typeGuard":null,"tryCatchPattern":"java\ntry {\n  validatePubsubMessage(msg, maxBatchSize);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"non-empty payload or at least one attribute\")) {\n    msg = new PubsubMessage(msg.getPayload(), addMarkerAttribute(msg.getAttributeMap()));\n  } else throw e;\n}","preventionTips":["Never emit PubsubMessage with empty payload AND empty attributes","Add a marker attribute for tombstone/empty events","Fix upstream transforms that produce zero-byte payloads","Unit-test message construction for empty-input cases"],"tags":["java","pubsub","validation","empty-payload"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-15T02:17:10.978Z"}