apache/iceberg · error · IllegalArgumentException
Cannot find unpartitioned spec in specs:
Error message
Cannot find unpartitioned spec in specs:
What it means
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.
Source
Thrown at core/src/main/java/org/apache/iceberg/TrackedFileAdapters.java:567
}
}
private static int resolveSpecId(TrackedFile file, Map<Integer, PartitionSpec> specsById) {
Integer specId = file.specId();
if (specId != null) {
Preconditions.checkArgument(
specsById.containsKey(specId), "Cannot find partition spec for spec ID: %s", specId);
return specId;
}
// A null spec ID means the file is unpartitioned; use the table's unpartitioned spec.
for (PartitionSpec spec : specsById.values()) {
if (spec.isUnpartitioned()) {
return spec.specId();
}
}
throw new IllegalArgumentException(
"Cannot find unpartitioned spec in specs: " + specsById.keySet());
}
}
View on GitHub (pinned to 86d9c8fc54)
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.
Example fix
// before
long specId = table.specs().values().stream().filter(PartitionSpec::isUnpartitioned)...; // may throw
// after
PartitionSpec unpartitioned = table.specs().values().stream()
.filter(PartitionSpec::isUnpartitioned).findFirst().orElse(null);
if (unpartitioned == null) { /* handle fully-partitioned table */ } Defensive patterns
Strategy: validation
Validate before calling
boolean hasUnpartitioned = table.specs().values().stream().anyMatch(PartitionSpec::isUnpartitioned);
if (!hasUnpartitioned) { /* take a partitioned-spec path */ } Try / catch
try { specId = findUnpartitionedSpecId(specs); } catch (IllegalArgumentException e) { specId = fallbackSpecId(specs); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Cannot update partition spec with unknown transform:
- Cannot add duplicate partition field name: %s
- Unsorted order ID must be 0
- Sort order ID 0 is reserved for unsorted order
- this.getClass().getName() + " doesn't implement addNonDefaul
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9ad6947b3a5d640d.
Report an issue: GitHub.