{"record":{"id":"379b0d1c32d1fb0f","repo":"apache/iceberg","slug":"cannot-find-a-partition-spec-in-iceberg-table-s-t-379b0d","errorCode":null,"errorMessage":"Cannot find a partition spec in Iceberg table %s that matches the partition columns (%s) in input table","messagePattern":"Cannot find a partition spec in Iceberg table (.+?) that matches the partition columns \\((.+?)\\) in input table","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkTableUtil.java","lineNumber":1044,"sourceCode":"        partitionNames.stream()\n            .map(name -> name.toLowerCase(Locale.ROOT))\n            .collect(Collectors.toList());\n    for (PartitionSpec icebergSpec : icebergTable.specs().values()) {\n      boolean allIdentity =\n          icebergSpec.fields().stream().allMatch(field -> field.transform().isIdentity());\n      if (allIdentity) {\n        List<String> icebergPartNames =\n            icebergSpec.fields().stream()\n                .map(PartitionField::name)\n                .map(name -> name.toLowerCase(Locale.ROOT))\n                .collect(Collectors.toList());\n        if (icebergPartNames.equals(partitionNamesLower)) {\n          return icebergSpec;\n        }\n      }\n    }\n\n    throw new IllegalArgumentException(\n        String.format(\n            \"Cannot find a partition spec in Iceberg table %s that matches the partition\"\n                + \" columns (%s) in input table\",\n            icebergTable, partitionNames));\n  }\n\n  /**\n   * Returns the first partition spec in an IcebergTable that shares the same names and ordering as\n   * the partition columns in a given Spark Table. Throws an error if not found\n   */\n  private static PartitionSpec findCompatibleSpec(\n      Table icebergTable, SparkSession spark, String sparkTable) throws AnalysisException {\n    List<String> parts = Lists.newArrayList(Splitter.on('.').limit(2).split(sparkTable));\n    String db = parts.size() == 1 ? \"default\" : parts.get(0);\n    String table = parts.get(parts.size() == 1 ? 0 : 1);\n\n    List<String> sparkPartNames =\n        spark.catalog().listColumns(db, table).collectAsList().stream()","sourceCodeStart":1026,"sourceCodeEnd":1062,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkTableUtil.java#L1026-L1062","documentation":"When importing Spark (Hive/managed) partitioned tables into Iceberg, SparkTableUtil matches the input table's partition columns against one of the Iceberg table's partition specs. If no Iceberg spec's field names (lowercased) equal the input partition columns, import fails with this IllegalArgumentException. Iceberg only imports data into an existing spec that already covers those columns.","triggerScenarios":"Calling SparkTableUtil.importSparkTable / snapshot partitioned Spark data where the source table's partition column names don't match (case-insensitively) any partition spec in the target Iceberg table.","commonSituations":"Source renamed or reordered partition columns vs the Iceberg spec; importing into an unpartitioned Iceberg table; case or transform mismatch (e.g. source partitioned by day, Iceberg spec by month) changing spec matching; copy-pasted import config from another table.","solutions":["Create the Iceberg target table with a partition spec whose field names exactly match the source partition columns (case-insensitive)","ALTER the Iceberg table's partitioning (replacing the spec) so a spec matches the source columns","Import into an unpartitioned table only if the source is unpartitioned","Verify partition column names/size with DESCRIBE on both tables before importing"],"exampleFix":"// before\ncatalog.createTable(ident, schema, PartitionSpec.unpartitioned());\nSparkTableUtil.importSparkTable(sparkSession, sourceTable, targetTable); // throws: no matching spec\n// after\nPartitionSpec spec = PartitionSpec.builderFor(schema).identity(\"part_date\").build(); // matches source columns\ncatalog.createTable(ident, schema, spec);\nSparkTableUtil.importSparkTable(sparkSession, sourceTable, targetTable);","handlingStrategy":"validation","validationCode":"List<String> srcParts = sourcePartitionNames.stream().map(String::toLowerCase).sorted().toList();\nboolean matched = targetSpecs.stream().anyMatch(s ->\n    s.fields().stream().map(f -> f.name().toLowerCase()).sorted().toList().equals(srcParts));","typeGuard":"if (!matched) {\n  throw new IllegalArgumentException(\"Target Iceberg specs do not match source partition columns\");\n}","tryCatchPattern":"try {\n  SparkTableUtil.importSparkTable(spark, source, target);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"Cannot find a partition spec\")) {\n    // recreate target table with a matching partition spec, then retry\n  }\n}","preventionTips":["Create target Iceberg tables with specs mirroring source partition columns","Compare DESCRIBE output of source and target before importing","Watch for case and transform differences in partition fields","Version-check import scripts against table schemas"],"tags":["spark","migration","partitioning","import"],"backgroundTag":"invalid-argument-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"}