{"record":{"id":"98eda807e7766d57","repo":"apache/iceberg","slug":"unsupported-isolation-level-isolationlevel-98eda8","errorCode":null,"errorMessage":"Unsupported isolation level: \" + isolationLevel","messagePattern":"Unsupported isolation level: \" \\+ isolationLevel","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkWrite.java","lineNumber":489,"sourceCode":"      for (DataFile file : files(messages)) {\n        numAddedFiles += 1;\n        overwriteFiles.addFile(file);\n      }\n\n      // the scan may be null if the optimizer replaces it with an empty relation (e.g. false cond)\n      // no validation is needed in this case as the command does not depend on the table state\n      if (scan != null) {\n        switch (isolationLevel) {\n          case SERIALIZABLE:\n            commitWithSerializableIsolation(\n                overwriteFiles, numOverwrittenFiles, numAddedFiles, summary);\n            break;\n          case SNAPSHOT:\n            commitWithSnapshotIsolation(\n                overwriteFiles, numOverwrittenFiles, numAddedFiles, summary);\n            break;\n          default:\n            throw new IllegalArgumentException(\"Unsupported isolation level: \" + isolationLevel);\n        }\n\n      } else {\n        commitOperation(\n            overwriteFiles,\n            String.format(\n                Locale.ROOT, \"overwrite with %d new data files (no validation)\", numAddedFiles),\n            summary);\n      }\n    }\n\n    private void commitWithSerializableIsolation(\n        OverwriteFiles overwriteFiles,\n        int numOverwrittenFiles,\n        int numAddedFiles,\n        WriteSummary summary) {\n      Long scanSnapshotId = scan.snapshotId();\n      if (scanSnapshotId != null) {","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkWrite.java#L471-L507","documentation":"SparkWrite.commit throws IllegalArgumentException when the write's configured isolation level is neither SERIALIZABLE nor SNAPSHOT. Iceberg only supports these two isolation modes for Copy-On-Write overwrite/DELETE operations; any other value reaching the commit path is a programming or configuration bug.","triggerScenarios":"Executing a dynamic-overwrite or DELETE (copy-on-write) SparkWrite whose isolationLevel field is not IsolationLevel.SERIALIZABLE or IsolationLevel.SNAPSHOT — typically set programmatically via SparkWriteOptions or a custom writer, or a non-exhaustive switch after adding a new Spark SQL isolation level.","commonSituations":"Custom Spark connectors or forks that set their own isolation level string/enum; Spark sessions or newer Spark versions introducing an isolation level Iceberg's switch does not handle; typos in write option mapping.","solutions":["Ensure the write is configured with 'serializable' or 'snapshot' isolation level only","Check the writer/builder code that constructs SparkWrite and the option it reads (write isolation level) for invalid values","If supporting a new Spark isolation level, extend the switch to map it onto SNAPSHOT or SERIALIZABLE commit paths","Upgrade Iceberg so the switch in SparkWrite.commit covers your Spark version's isolation levels"],"exampleFix":"// before\nwriteConf.isolationLevel() // returns e.g. READ_COMMITTED\n// after\nconf.set(\"spark.sql.sources.writeIsolationLevel\", \"serializable\"); // or snapshot","handlingStrategy":"validation","validationCode":"String level = spark.conf().get(\"spark.sql.sources.writeIsolationLevel\", \"serializable\");\nif (!level.equalsIgnoreCase(\"serializable\") && !level.equalsIgnoreCase(\"snapshot\")) {\n  throw new IllegalArgumentException(\"isolationLevel must be 'serializable' or 'snapshot', got: \" + level);\n}","typeGuard":null,"tryCatchPattern":"try { write.commit(); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Unsupported isolation level\")) { /* reconfigure and retry */ } else throw e; }","preventionTips":["Only configure 'serializable' or 'snapshot' as Iceberg write isolation levels","Keep the isolation-level option mapping in sync between Spark SQL config and Iceberg options","Test custom writers against both supported enum values before deploying"],"tags":["spark","isolation-level","configuration","illegal-argument"],"backgroundTag":"invalid-enum-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}