{"record":{"id":"9ad6947b3a5d640d","repo":"apache/iceberg","slug":"cannot-find-unpartitioned-spec-in-specs","errorCode":null,"errorMessage":"Cannot find unpartitioned spec in specs: ","messagePattern":"Cannot find unpartitioned spec in specs: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/TrackedFileAdapters.java","lineNumber":567,"sourceCode":"    }\n  }\n\n  private static int resolveSpecId(TrackedFile file, Map<Integer, PartitionSpec> specsById) {\n    Integer specId = file.specId();\n    if (specId != null) {\n      Preconditions.checkArgument(\n          specsById.containsKey(specId), \"Cannot find partition spec for spec ID: %s\", specId);\n      return specId;\n    }\n\n    // A null spec ID means the file is unpartitioned; use the table's unpartitioned spec.\n    for (PartitionSpec spec : specsById.values()) {\n      if (spec.isUnpartitioned()) {\n        return spec.specId();\n      }\n    }\n\n    throw new IllegalArgumentException(\n        \"Cannot find unpartitioned spec in specs: \" + specsById.keySet());\n  }\n}\n","sourceCodeStart":549,"sourceCodeEnd":571,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/TrackedFileAdapters.java#L549-L571","documentation":"TrackedFileAdapters needs the spec ID of the unpartitioned partition spec within a table's specs map. If none of the specs in specsById is unpartitioned (i.e., the table was always partitioned), the lookup helper throws IllegalArgumentException listing the spec IDs it searched.","triggerScenarios":"An adapter path requires an unpartitioned spec (e.g., to interpret a file written before partitioning or to map an empty partition key) but the table's metadata contains only partitioned specs.","commonSituations":"Tracking files on a table that was partitioned from creation, with code that assumes an unpartitioned spec (spec 0) always exists; metadata rewritten so spec 0 is partitioned.","solutions":["Check that the table actually has an unpartitioned spec (specs.containsValue matching isUnpartitioned) before invoking the adapter path.","Pass the correct target spec ID explicitly instead of relying on the unpartitioned-spec lookup.","Guard the call: iterate specsById yourself and fall back when no unpartitioned spec exists."],"exampleFix":"// before\nlong specId = table.specs().values().stream().filter(PartitionSpec::isUnpartitioned)...; // may throw\n\n// after\nPartitionSpec unpartitioned = table.specs().values().stream()\n    .filter(PartitionSpec::isUnpartitioned).findFirst().orElse(null);\nif (unpartitioned == null) { /* handle fully-partitioned table */ }","handlingStrategy":"validation","validationCode":"boolean hasUnpartitioned = table.specs().values().stream().anyMatch(PartitionSpec::isUnpartitioned);\nif (!hasUnpartitioned) { /* take a partitioned-spec path */ }","typeGuard":null,"tryCatchPattern":"try { specId = findUnpartitionedSpecId(specs); } catch (IllegalArgumentException e) { specId = fallbackSpecId(specs); }","preventionTips":["Never assume spec 0 is unpartitioned; tables may be partitioned from creation.","Inspect specsById for an unpartitioned spec before invoking adapter paths needing one.","Handle fully-partitioned tables explicitly in tracking tooling."],"tags":["illegal-argument","partition-spec","table-metadata"],"backgroundTag":"resource-not-found","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"}