{"record":{"id":"47ad465f0c9d1f64","repo":"apache/iceberg","slug":"s-does-not-have-a-format-version","errorCode":null,"errorMessage":"%s does not have a format version","messagePattern":"(.+?) does not have a format version","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/TableUtil.java","lineNumber":40,"sourceCode":"\npublic class TableUtil {\n  private TableUtil() {}\n\n  /** Returns the format version of the given table */\n  public static int formatVersion(Table table) {\n    Preconditions.checkArgument(null != table, \"Invalid table: null\");\n\n    if (table instanceof SerializableTable) {\n      SerializableTable serializableTable = (SerializableTable) table;\n      return serializableTable.formatVersion();\n    } else if (table instanceof HasTableOperations) {\n      HasTableOperations ops = (HasTableOperations) table;\n      return ops.operations().current().formatVersion();\n    } else if (table instanceof BaseMetadataTable) {\n      BaseMetadataTable metadataTable = (BaseMetadataTable) table;\n      return metadataTable.table().operations().current().formatVersion();\n    } else {\n      throw new IllegalArgumentException(\n          String.format(\"%s does not have a format version\", table.getClass().getSimpleName()));\n    }\n  }\n\n  /** Returns the metadata file location of the given table */\n  public static String metadataFileLocation(Table table) {\n    Preconditions.checkArgument(null != table, \"Invalid table: null\");\n\n    if (table instanceof SerializableTable) {\n      SerializableTable serializableTable = (SerializableTable) table;\n      return serializableTable.metadataFileLocation();\n    } else if (table instanceof HasTableOperations) {\n      HasTableOperations ops = (HasTableOperations) table;\n      return ops.operations().current().metadataFileLocation();\n    } else if (table instanceof BaseMetadataTable) {\n      return ((BaseMetadataTable) table).table().operations().current().metadataFileLocation();\n    } else {\n      throw new IllegalArgumentException(","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/TableUtil.java#L22-L58","documentation":"TableUtil.formatVersion(Table) extracts the format version from the table's operations, but only for tables whose operations implement HasTableOperations or that are BaseMetadataTable instances. Any other Table implementation has no accessible operations/current metadata, so IllegalArgumentException is thrown. It's a guard against asking a non-standard table wrapper (e.g. mocks, static tables, custom wrappers) for a version it cannot provide.","triggerScenarios":"TableUtil.formatVersion(table) (directly or via TableUtil.supportsRowLineage) with a Table that is neither HasTableOperations nor BaseMetadataTable — e.g. StaticTable, a custom Table decorator, or a test mock.","commonSituations":"Code that inspects format version to gate v2+ features (row lineage, deletes) run against static or wrapped tables; library users passing engine-adapter table wrappers into TableUtil helpers; version-upgrade scenarios where a Table implementation stopped implementing HasTableOperations.","solutions":["Ensure the Table handle comes from a catalog/BaseTable so operations() implements HasTableOperations","Use TableUtil.formatVersion only on real base tables; unwrap metadata-table wrappers via .table() first","Check supportsRowLineage/similar callers and exclude static/custom tables before calling","If you own a Table wrapper, implement HasTableOperations so TableUtil can read the metadata"],"exampleFix":"// before\nint version = TableUtil.formatVersion(staticTable); // throws\n// after\nTable base = (staticTable instanceof BaseMetadataTable)\n    ? ((BaseMetadataTable) staticTable).table() : staticTable;\nint version = TableUtil.formatVersion(base);","handlingStrategy":"type-guard","validationCode":"boolean canReadFormatVersion(Table t) {\n  return t instanceof BaseMetadataTable\n      || (t.operations() instanceof HasTableOperations);\n}","typeGuard":"Integer safeFormatVersion(Table t) {\n  if (t instanceof BaseMetadataTable) t = ((BaseMetadataTable) t).table();\n  return (t.operations() instanceof HasTableOperations)\n      ? ((HasTableOperations) t.operations()).operations() == null ? null\n        : ((HasTableOperations) t).operations().current().formatVersion()\n      : null;\n}","tryCatchPattern":"try { v = TableUtil.formatVersion(table); }\ncatch (IllegalArgumentException e) { v = null; /* non-standard table impl */ }","preventionTips":["Only call TableUtil helpers on BaseTable handles from a catalog","Unwrap BaseMetadataTable before feature-gating checks","Avoid passing static or custom wrapper tables into format-version checks","Have custom Table implementations implement HasTableOperations"],"tags":["format-version","table-util","argument-validation","iceberg"],"backgroundTag":"incompatible-source-type","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}