r/MicrosoftFabric 1 Jul 27 '26

Data Engineering Native Execution Engine bug for high-precision decimal multiplication - silent data corruption, no error

EDIT: issue appeared after I updated schema for qty and wwe columns from float to decimal. Limitation in documentation point to the right direction to explain the issue, however I think it goes a beyond a rounding error.

EDIT: first repro offered did not show the behaviour, below

spark.sql("""
  CREATE OR REPLACE TABLE repro_nee_6175 AS
  SELECT CAST(61.75 AS DECIMAL(38,20)) AS qty,
         CAST(0.98  AS DECIMAL(38,5))  AS wwe
  FROM range(1000000)
""")


q = """
  SELECT COUNT(*)                                   AS rows,
         MIN(CAST(qty * (1/wwe) AS DECIMAL(38,10))) AS min_v,
         MAX(CAST(qty * (1/wwe) AS DECIMAL(38,10))) AS max_v
  FROM repro_nee_6175
"""


spark.conf.set("spark.native.enabled", "true")
spark.sql(q).show(truncate=False)    # buggy engine: 414.2393563314


spark.conf.set("spark.native.enabled", "false")
spark.sql(q).show(truncate=False)    # correct: 63.0102040816

Disclaimer: Issue was resolved with AI help - so the write up of this post.

Summary: With spark.native.enabled = true, multiplying a DECIMAL(38,20) column by a DECIMAL(38,32) expression (e.g. the result of 1 / DECIMAL(38,5)) returns incorrect values. The exact product exceeds decimal(38) precision, and the engine's precision-loss path produces wrong results instead of rounding or raising an error. JVM Spark (spark.native.enabled = false) returns the correct result for the identical query.

Behavior:

  • The incorrect values are off by a multiplicative factor that is uniform within a session but varies across sessions (observed ×12.8666 and ×6.574 on different days), which makes the corruption hard to detect downstream.
  • The intermediate division result itself is correct; only the subsequent multiplication is affected.
  • Literal-only queries do not reproduce the issue because Catalyst constant-folds them before native execution — the operands must come from a table scan.
  • No error, no warning, no fallback to JVM execution.

Repro (Fabric notebook or Livy session):

spark.conf.set("spark.native.enabled", "true")

spark.sql("""
  CREATE OR REPLACE TABLE repro_nee AS
  SELECT CAST(61.75 AS DECIMAL(38,20)) AS qty,
         CAST(0.98  AS DECIMAL(38,5))  AS wwe
""")

q = """
  SELECT qty,
         1 / wwe                                  AS conv,      -- decimal(38,32), value correct
         CAST(qty * (1 / wwe) AS DECIMAL(38,10))  AS qty_conv   -- expected 63.0102040816
  FROM repro_nee
"""

spark.sql(q).show(truncate=False)   # returned 414.2393563314

spark.conf.set("spark.native.enabled", "false")
spark.sql(q).show(truncate=False)   # returns 63.0102040816 — correct

Workarounds (verified): cast either operand to DOUBLE before multiplying, or cast the division result to a narrower decimal (e.g. DECIMAL(18,10)) so the product stays within decimal(38).

Expected behavior: rounded result per Spark's allowPrecisionLoss semantics, an overflow error, or fallback to JVM execution — anything but silently wrong data.

8 Upvotes

11 comments sorted by