Skip to content

bug: TypeFromJson throws an uncaught exception on a decimal precision above 38 #1009

Closed as not planned

Description

@LuciferYang

Summary

TypeFromJson parses decimal(P, S) with a regex and passes the numbers straight to the DecimalType constructor. That constructor checks precision with ICEBERG_CHECK_OR_DIE, which throws IcebergError unconditionally (it is not gated on NDEBUG). So a schema type string such as "decimal(39, 2)" throws out of a function that returns Result, and the caller gets an uncaught exception instead of a JsonParseError.

Root cause

src/iceberg/json_serde.cc, decimal branch of TypeFromJson:

ICEBERG_ASSIGN_OR_RAISE(auto precision, StringUtils::ParseNumber<int32_t>(match[1].str()));
ICEBERG_ASSIGN_OR_RAISE(auto scale, StringUtils::ParseNumber<int32_t>(match[2].str()));
return std::make_unique<DecimalType>(precision, scale);  // throws for precision > 38

Nothing on the parse chain (TypeFromJson → FieldFromJson → SchemaFromJson → TableMetadataFromJson) catches it.

Impact

TypeFromJson is reached when reading table metadata (TableMetadataUtil::Read) and when parsing REST bodies that carry a schema, such as LoadTable responses and CreateTableRequest. A spec-conforming writer never emits a precision above 38, so the trigger is a corrupt or non-conforming metadata file. That input should come back as a parse error; today it terminates a caller that checks the Result but does not wrap the call in try. This is the same class as #878 and #982. SECURITY-THREAT-MODEL.md treats catalog metadata as trusted, so this is an API-contract issue, not a security one.

Proposed fix

Check precision > DecimalType::kMaxPrecision before constructing the type and return JsonParseError. The regex only captures digits and ParseNumber already rejects int32 overflow, so a lower-bound check is not needed. Scale is not constrained by the constructor (or by Java's Types.DecimalType), so it stays as is.

Activity

  1. LuciferYang commented on Oct 14, 2026

    @LuciferYang
    ContributorAuthor

    Closing as not planned: only malformed metadata that no conforming writer produces can trigger this. See #1010.

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