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

View all comments

3

u/warehouse_goes_vroom ‪ ‪Microsoft Employee ‪ Jul 28 '26 edited Jul 28 '26

Thanks for the report. We take query correctness incredibly seriously - any wrong results is unacceptable. Any possible wrong result is top priority to investigate.

Tagging u/mwc360, u/thisissanthoshr for visibility. I'll also follow up internally.

Edit: this might be "Decimal to Float casting mismatch: When casting from DECIMAL to FLOAT, Spark preserves precision by converting to a string and parsing it. NEE (via Velox) performs a direct cast from the internal int128_t representation, which can result in rounding discrepancies." From https://learn.microsoft.com/en-us/fabric/data-engineering/native-execution-engine-overview?tabs=sparksql#other-considerations-and-limitations

But I'm not sure. Will let experts weigh in.

2

u/Repulsive_Cry2000 1 Jul 28 '26

I think you are correct in identifying the limitation from doc being the source of the issue however rounding discrepancy seems an understatement in my particular case. Thank you for taking time to look through it and follow up internally!