{"record":{"id":"27458768e7dc334e","repo":"apache/iceberg","slug":"v4-manifests-are-not-bound-to-a-single-partition-s","errorCode":null,"errorMessage":"v4 manifests are not bound to a single partition spec","messagePattern":"v4 manifests are not bound to a single partition spec","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/TrackedFileAdapters.java","lineNumber":439,"sourceCode":"    private final TrackedFile file;\n\n    private TrackedManifestFile(TrackedFile file) {\n      this.file = file;\n    }\n\n    @Override\n    public String path() {\n      return file.location();\n    }\n\n    @Override\n    public long length() {\n      return file.fileSizeInBytes();\n    }\n\n    @Override\n    public int partitionSpecId() {\n      throw new UnsupportedOperationException(\n          \"v4 manifests are not bound to a single partition spec\");\n    }\n\n    @Override\n    public ManifestContent content() {\n      switch (file.contentType()) {\n        case DATA_MANIFEST:\n          return ManifestContent.DATA;\n        case DELETE_MANIFEST:\n          return ManifestContent.DELETES;\n        default:\n          throw new UnsupportedOperationException(\n              \"Unsupported content type for manifests: \" + file.contentType());\n      }\n    }\n\n    @Override\n    public long sequenceNumber() {","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/TrackedFileAdapters.java#L421-L457","documentation":"Starting with format version 4, manifests are no longer bound to exactly one partition spec; each manifest entry carries its own spec ID. This adapter exposes a v4 ManifestFile through the older single-spec ManifestReader interface, which has a per-manifest partitionSpecId(). Since no single value exists, the accessor intentionally throws UnsupportedOperationException.","triggerScenarios":"Calling partitionSpecId() on the ManifestFileAdapter produced for a v4 manifest file (TrackedFileAdapters wrapping a v4 ManifestFile into the legacy ManifestFile interface), e.g. when planning scans or listing manifests and reading manifest.specId() on a v3->v4 table.","commonSituations":"Code written for v1-v3 tables reading manifest.specId() now running against a v4 table; third-party tools/integrations that assume one spec per manifest; maintenance jobs (rewrite/expire) that inspect partition specs via the legacy adapter.","solutions":["Use the v4-aware API: read per-entry partition spec IDs from manifest entries instead of the manifest-level specId()","Check the table's formatVersion and branch your code: specId() for v<=3, entry-level specs for v4","Upgrade dependent code/tooling to an Iceberg release with v4 manifest support","If a single spec is genuinely required, keep the table at format version <= 3"],"exampleFix":"// before\nint specId = (int) manifestFile.partitionSpecId();\n// after\nint specId = TableUtil.formatVersion(table) >= 4\n    ? entryFile.partitionSpecId()   // entry-level spec from v4 manifest entries\n    : (int) manifestFile.partitionSpecId();","handlingStrategy":"type-guard","validationCode":"boolean supportsManifestSpecId(Table table) {\n  return TableUtil.formatVersion(table) < 4;\n}","typeGuard":"Long safeSpecId(ManifestFile mf, int formatVersion) {\n  return formatVersion >= 4 ? null : (long) mf.partitionSpecId();\n}","tryCatchPattern":"long specId;\ntry { specId = mf.partitionSpecId(); }\ncatch (UnsupportedOperationException e) {\n  // v4: read per-entry spec IDs instead\n  specId = -1;\n}","preventionTips":["Gate manifest.specId() usage on formatVersion < 4","Use per-entry partition spec APIs for v4 tables","Keep integrations/tools updated before upgrading tables to v4","Write a compatibility layer instead of assuming one spec per manifest"],"tags":["v4","manifest","partition-spec","unsupported-operation","iceberg"],"backgroundTag":"unsupported-operation","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"}