Skip to content

[Bug] PostgreSQL and MongoDB: an item containing U+0000 returns InternalServerError; the service accepts it #364

Description

@LeeroyHannigan

Summary

DynamoDB accepts the character U+0000 (NUL) anywhere a string can appear: partition keys, sort keys, index keys, non-key string values, strings inside lists, map keys, and top-level attribute names. Measured today against the service on a scratch table; every one of eight PutItem cases returned 200 and read back byte-identical with GetItem.

ExtendDB's PostgreSQL backend returns 500 InternalServerError for every one of those cases, including a plain non-key string value. The MongoDB backend accepts NUL in keys and values but returns 500 when NUL appears in an attribute name (top level or map key). SQLite matches the service in all eight cases. A Query whose key value contains NUL also returns 500 on PostgreSQL.

Reproduction

Table pk S, sk S, GSI gsi1 on g S. Each case is one PutItem, followed by a consistent GetItem where the write succeeded.

case service PostgreSQL MongoDB SQLite
NUL inside pk 200, round-trips 500 200, round-trips 200, round-trips
NUL inside sk 200, round-trips 500 200, round-trips 200, round-trips
NUL inside GSI key g 200, round-trips 500 200, round-trips 200, round-trips
NUL inside a non-key string 200, round-trips 500 200, round-trips 200, round-trips
NUL inside a string in a list 200, round-trips 500 200, round-trips 200, round-trips
NUL as the whole non-key string 200, round-trips 500 200, round-trips 200, round-trips
NUL inside a map key 200, round-trips 500 500 200, round-trips
NUL inside a top-level attribute name 200, round-trips 500 500 200, round-trips
Query on gsi1 with a NUL key value 200 500 200 200

Server logs behind the 500s:

PostgreSQL, key columns: invalid byte sequence for encoding "UTF8": 0x00 (TEXT cannot hold a NUL byte).
PostgreSQL, item body: unsupported Unicode escape sequence (jsonb rejects \u0000).
MongoDB, attribute names: cstrings cannot contain null bytes (BSON field names are C strings).

The message text and error code on the wire is the generic InternalServerError: Internal server error, so a client cannot tell what was wrong with the item.

Measured on servers built from fix/postgres-key-collation (parent of the current builder work); the storage paths involved are unchanged from main.

Expected

Either behavior would be acceptable, and the first is the one that matches the service:

  1. Store and return U+0000 faithfully on every backend. On PostgreSQL this needs an encoding for key columns and for the jsonb body (for example a reversible escape applied on write and removed on read, or bytea key columns). On MongoDB it needs an encoding for field names only.
  2. If a backend cannot store the item, reject it with a 400 ValidationException naming the limitation, consistently across every operation that accepts a string (PutItem, UpdateItem, BatchWriteItem, TransactWriteItems, Query and Scan condition values, ExpressionAttributeValues), so the caller gets a clear error instead of a 500 and the divergence is documented in docs/dynamodb-limits.md.

Option 2 is a documented divergence from the service; option 1 is fidelity. Either way the 500 is wrong.

Notes

The service's GSI Query for the NUL key returned Count 0 on the immediate read after the PutItem, which is index propagation on a fresh table, not a rejection; the base-table Scan counted all eight items.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions