Uh oh!
There was an error while loading. Please reload this page.
Spark: Fix type mismatch in SPJ with bucket partition key on string column - #16424
Spark: Fix type mismatch in SPJ with bucket partition key on string column#16424ammarchalifah wants to merge 4 commits into
Conversation
ammarchalifah
commented
May 19, 2026
This PR is a re-implementation of this closed PR: #15555 I was the reporter that filed the bug report, and really needed this bug to be fixed. |
ammarchalifah
commented
May 26, 2026
@huaxingao could you review this PR when you have time? |
RussellSpitzer
commented
May 27, 2026
Generally we only do a single Spark version (the latest) for changes followed by a backport PR to avoid duplicates during review |
RussellSpitzer
commented
May 27, 2026
My gut reading here is that we shouldn't be changing StructInternalRow, calling "getString" on a non string object should not default to calling "toString" on that object. This would just silently widen types in a way that we don't do anywhere else. It feels like we are fixing a bad caller by changing the behavior rather than fixing the caller. |
RussellSpitzer
commented
May 27, 2026
I couldn't get a repo on 4.0 or 4.1, I think this is already fixed in the newer Spark versions (calling the correct function) That leaves 3.5 with our custom code. Let me take a look there |
ammarchalifah
commented
May 27, 2026
Got it, I will change this PR to reflect this convention. |
ammarchalifah
commented
May 27, 2026
Recently I upgraded my EMR to EMR 8.0.0 (running Spark 4.0.2 in the background), and using Iceberg 11, but the problem persisted. |
I am running the tests you added to the PR, so far I have not reproduced the issue on any Spark build. Took your PR, removed the changes to Internal Row. Ran for example Passed
|
…olumn Co-authored-by: Cursor <cursoragent@cursor.com>
e37c145 to
5147ba0Compareammarchalifah
commented
May 27, 2026
Hmm, this is confusing. In my production case, my actual table has more partition keys, and I'm doing a join on a subset of key with |
ammarchalifah
commented
May 27, 2026
RussellSpitzer
commented
May 27, 2026
That could be it, it's possible the catalog is replying with the incorrect types? or it could be something EMR specific? |
ammarchalifah
commented
May 27, 2026
Oh, there is one more hypothesis that I'm checking right now. My workload is using |
ammarchalifah
commented
May 27, 2026
Example of my spec from Iceberg metadata Error message (AWS Glue catalog, EMR 8.0.0, Spark 4.0.2) |
ammarchalifah
commented
May 28, 2026
Managed to reproduce the issue with a lightweight Spark job triggered on EMR 8.0.0. I put the full repro script + full |
ammarchalifah
commented
May 28, 2026
Changed the test case to test SPJ for |
ammarchalifah
commented
May 28, 2026
Reproduced a test suite to mimic the behaviour with vanilla Spark & Hadoop catalog. The error message is slightly different, but the gist of the issue is the same Happens both in When partition columns are reorganized e.g. |
ammarchalifah
commented
May 28, 2026
Seems like the issue is already fixed on Spark 4.2, but not backported to earlier versions. Related PR: apache/spark#54330 |
RussellSpitzer
commented
May 28, 2026
Thanks for looking into that, If that's the case I would recommend we don't do this patch for Iceberg but push for backporting the fix on Spark |
ammarchalifah
commented
May 29, 2026
Agree on the not fixing this on Iceberg part.
However, the bug still exists, as demonstrated by the newly added test in this PR + the EMR repro script in the issue. |
This pull request has been marked as stale due to 30 days of inactivity. It will be closed in 1 week if no further activity occurs. If you think that’s incorrect or this pull request requires a review, please simply write any comment. If closed, you can revive the PR at any time and @mention a reviewer or discuss it on the dev@iceberg.apache.org list. Thank you for your contributions. |
This pull request has been closed due to lack of activity. This is not a judgement on the merit of the PR in any way. It is just a way of keeping the PR queue manageable. If you think that is incorrect, or the pull request requires review, you can revive the PR at any time. |

Problem
When a table is partitioned by
bucket(N, string_column), the bucket transform produces anIntegerpartition value. During Storage Partitioned Joins (SPJ), Spark reads partition values throughStructInternalRow, which callsstruct.get(ordinal, CharSequence.class)ingetUTF8StringInternal(). This assumes the value is always aCharSequence, causing aClassCastException:This affects any SPJ query (e.g.
MERGE INTOorJOIN) on tables partitionedwith
bucket(N, string_column).Fix
Changed
getUTF8StringInternal()to usestruct.get(ordinal, Object.class)instead ofstruct.get(ordinal, CharSequence.class), then callvalue.toString(). This follows the same pattern already used bygetBinaryInternal()in the same class, which usesObject.classto handle multiple possible runtime types.The fix is applied to all Spark versions: 3.4, 3.5, 4.0, and 4.1.
Testing
testJoinsWithBucketingOnStringColumnusing the existingcheckJoinhelper to cover bucket-only partitioning on string columns.testJoinsWithIdentityAndBucketOnStringColumnas a targeted regression test for the exact scenario from the issue: identity + bucket partitioning on a string column with an SPJ join.Both tests are added consistently across all 4 Spark versions.
Notes
AI tools were used to assist with drafting this change. I have reviewed and
validated the logic, tests, and code style end-to-end.
Closes#15349