Skip to content

Fix DynamoDB Rounded error for numbers with trailing zeros#4717

Open
veeceey wants to merge 1 commit intoboto:developfrom
veeceey:fix-dynamodb-big-number-deserialization
Open

Fix DynamoDB Rounded error for numbers with trailing zeros#4717
veeceey wants to merge 1 commit intoboto:developfrom
veeceey:fix-dynamodb-big-number-deserialization

Conversation

@veeceey
Copy link
Copy Markdown

@veeceey veeceey commented Feb 10, 2026

Summary

Fixes #4693

  • Numbers with non-significant trailing zeros (e.g. 1234567895171680000000000000000000000000) cause decimal.Rounded exceptions during serialization and deserialization because Python's Decimal counts trailing zeros as significant digits, exceeding DYNAMODB_CONTEXT's 38-digit precision limit
  • The fix normalizes numbers before applying DYNAMODB_CONTEXT to strip non-significant trailing zeros, using a separate _NORMALIZE_CONTEXT with wider precision (100 digits) so normalization itself never silently loses significant digits
  • This affects both TypeSerializer._serialize_n and TypeDeserializer._deserialize_n, as well as number sets

Reproduction

from boto3.dynamodb.types import TypeDeserializer

deserializer = TypeDeserializer()
# This raises decimal.Rounded before the fix:
deserializer.deserialize({'N': '1234567895171680000000000000000000000000'})

The number 1234567895171680000000000000000000000000 has only 16 significant digits but its string representation has 40 characters. DynamoDB supports up to 38 digits of precision, so this number is perfectly valid and is accepted by other AWS SDKs (Go, Java, etc.).

Approach

The root cause is that DYNAMODB_CONTEXT.create_decimal(value) treats all digits in the string representation as significant. A value like "1234567895171680000000000000000000000000" is seen as having 40 digits of precision, which exceeds the 38-digit limit and triggers the Rounded trap.

The fix introduces _NORMALIZE_CONTEXT (a decimal.Context with prec=100 and no traps) and calls _NORMALIZE_CONTEXT.normalize(Decimal(value)) before passing to DYNAMODB_CONTEXT.create_decimal(). This converts trailing zeros into an exponent (e.g. 1.23456789517168E+39) so only significant digits count toward the precision check. The wider precision of 100 ensures normalization never rounds values that fit within DynamoDB's 38-digit limit.

Test plan

  • All 39 existing tests/unit/dynamodb/test_types.py tests pass unchanged
  • All 183 DynamoDB unit tests pass (tests/unit/dynamodb/)
  • Added 5 new test cases covering:
    • Serialization of large integers with trailing zeros
    • Serialization of Decimal values with trailing zeros
    • Deserialization of positive numbers with trailing zeros
    • Deserialization of negative numbers with trailing zeros
    • Deserialization of number sets containing values with trailing zeros

…zeros

Numbers like 1234567895171680000000000000000000000000 are valid in
DynamoDB (16 significant digits) but cause a decimal.Rounded exception
because Python's Decimal treats the trailing zeros as significant,
giving 40 digits which exceeds DYNAMODB_CONTEXT's 38-digit precision.

The fix normalizes numbers before applying DYNAMODB_CONTEXT to strip
non-significant trailing zeros. A separate _NORMALIZE_CONTEXT with
wider precision (100) is used so that normalization itself never
silently loses significant digits.

Fixes boto#4693

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@veeceey
Copy link
Copy Markdown
Author

veeceey commented Feb 19, 2026

Friendly ping - any chance someone could take a look at this when they get a chance? Happy to make any changes if needed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DynamoDB deserialization throws exception for big numbers

1 participant