apache/iceberg · warning
Reading partition spec from manifest file metadata is…
Error message
Reading partition spec from manifest file metadata is deprecated and will be removed in the 2.0.0 release. Pass specsById to avoid reading from file metadata: {} What it means
Constructing a ManifestReader without a specsById map forces the reader to read and parse the partition spec from the manifest file's own metadata. This is deprecated (scheduled for removal in 2.0.0) because reading specs from file metadata is slow and unnecessary when the table metadata's spec map is available; the WARN prints the manifest location.
Solutions
- Pass the table's spec map: use ManifestFiles.open(manifest, fileIO, specsById) (or read(manifest, fileIO, specsById)) obtained from table.operations().current().specsById().
- If only a ManifestFile is available, resolve specsById from the current TableMetadata instead of letting the reader parse the file.
- Update dependent frameworks/connectors to an Iceberg version whose internal readers pass specsById.
- Prepare for 2.0.0 where reading from file metadata is removed — the call will no longer work.
Example fix
// before ManifestReader<DataFile> reader = ManifestFiles.read(manifest, fileIO); // after Map<Integer, PartitionSpec> specsById = table.operations().current().specsById(); ManifestReader<DataFile> reader = ManifestFiles.read(manifest, fileIO, specsById);
Defensive patterns
Strategy: type-guard
Validate before calling
if (manifest.hasCachedSpec() == false && specsById == null) {
throw new IllegalArgumentException("specsById is required to read manifests without cached specs");
} Type guard
static boolean canReadWithoutSpecs(ManifestFile manifest) {
return manifest.hasCachedSpec(); // if false, always pass specsById
} Prevention
- Always call ManifestFiles.read/open with the specsById overload when TableMetadata is available.
- Fetch specsById via table.operations().current().specsById() in custom readers.
- Update custom integrations before upgrading to 2.0.0 where file-metadata spec reading is removed.
- Keep internal reader code in sync with ManifestFiles API changes per release notes.
When it happens
Trigger: Calling ManifestFiles.read(manifest) / new ManifestReader(...) without passing specsById, instead of the specsById-aware open(manifest, io, specsById) variants — commonly in custom scan/cleanup code or older integration paths.
Common situations: Custom maintenance or inspection code written against the old ManifestFiles API; third-party integrations not yet updated for the specsById parameter; copy-pasted example code from pre-1.x Iceberg.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- Cannot add duplicate partition field name
- Cannot add partition field to non-Iceberg table: $table
- Cannot drop partition field in non-Iceberg table: $table
- Cannot find unpartitioned spec in specs:
- Cannot rewrite manifests in a
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/94a764a07996c8d4.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/ManifestReader.java:159
int specId,
Map<Integer, PartitionSpec> specsById,
InheritableMetadata inheritableMetadata,
Long firstRowId,
boolean isCommitted,
FileType content) {
Preconditions.checkArgument(
firstRowId == null || content == FileType.DATA_FILES,
"First row ID is not valid for delete manifests");
this.file = file;
this.inheritableMetadata = inheritableMetadata;
this.firstRowId = firstRowId;
this.isCommitted = isCommitted;
this.content = content;
if (specsById != null) {
this.spec = specsById.get(specId);
} else {
LOG.warn(
"Reading partition spec from manifest file metadata is deprecated and will be "
+ "removed in the 2.0.0 release. Pass specsById to avoid reading from file metadata: {}",
file.location());
this.spec = readPartitionSpec(file);
}
this.fileSchema = new Schema(DataFile.getType(spec.rawPartitionType()).fields());
}
private <T extends ContentFile<T>> PartitionSpec readPartitionSpec(InputFile inputFile) {
Map<String, String> metadata = readMetadata(inputFile);
int specId = TableMetadata.INITIAL_SPEC_ID;
String specProperty = metadata.get("partition-spec-id");
if (specProperty != null) {
specId = Integer.parseInt(specProperty);
}
View on GitHub (pinned to 86d9c8fc54)