apache/iceberg · error · IllegalArgumentException
Cannot write delete files in a v1 table
Error message
Cannot write delete files in a v1 table
What it means
Delete files (position/equality deletes) require format version 2 or later; writeDeleteManifest explicitly throws IllegalArgumentException when asked to write a delete manifest for a v1 table since v1 has no delete-file support.
Source
Thrown at core/src/main/java/org/apache/iceberg/ManifestFiles.java:379
/**
* Create a new {@link ManifestWriter} for the given format version with custom writer properties.
*
* @param formatVersion a target format version
* @param spec a {@link PartitionSpec}
* @param outputFile an {@link EncryptedOutputFile} where the manifest will be written
* @param snapshotId a snapshot ID for the manifest entries, or null for an inherited ID
* @param writerProperties properties passed through to the underlying file writer
* @return a manifest writer
*/
public static ManifestWriter<DeleteFile> writeDeleteManifest(
int formatVersion,
PartitionSpec spec,
EncryptedOutputFile outputFile,
Long snapshotId,
Map<String, String> writerProperties) {
switch (formatVersion) {
case 1:
throw new IllegalArgumentException("Cannot write delete files in a v1 table");
case 2:
return new ManifestWriter.V2DeleteWriter(spec, outputFile, snapshotId, writerProperties);
case 3:
return new ManifestWriter.V3DeleteWriter(spec, outputFile, snapshotId, writerProperties);
case 4:
return new ManifestWriter.V4DeleteWriter(spec, outputFile, snapshotId, writerProperties);
}
throw new UnsupportedOperationException(
"Cannot write manifest for table version: " + formatVersion);
}
/**
* Encode the {@link ManifestFile} to a byte array by using avro encoder.
*
* @param manifestFile a {@link ManifestFile}, which should always be a {@link
* GenericManifestFile}.
* @return the binary data.
* @throws IOException if encounter any IO error when encoding.View on GitHub (pinned to 86d9c8fc54)
Solutions
- Migrate the table to format version 2 (rewrite table metadata with format-version=2) before writing delete files
- Use overwrite/rewrite-based delete semantics for v1 tables instead of delete files
- Verify the table's format-version property before running delete jobs
Example fix
// before: writing delete manifest against a v1 table ManifestFiles.writeDeleteManifest(1, spec, outputFile, snapshotId, props); // after: migrate table to v2 first, then ManifestFiles.writeDeleteManifest(2, spec, outputFile, snapshotId, props);
Defensive patterns
Strategy: validation
Validate before calling
if (table.ops().current().formatVersion() < 2) {
throw new IllegalStateException("Delete files require format version >= 2; migrate the table first");
} Try / catch
try {
ManifestFiles.writeDeleteManifest(formatVersion, spec, out, snapshotId, props);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("v1 table")) { /* switch to overwrite semantics or migrate */ }
else throw e;
} Prevention
- Migrate legacy v1 tables to v2 before enabling row-level deletes
- Check format-version before running MERGE/DELETE jobs
- Use overwrite-based deletes for v1 tables
When it happens
Trigger: Calling ManifestFiles.writeDeleteManifest with formatVersion 1, or performing a delete/copy-on-write operation against a table whose format-version is 1.
Common situations: Trying row-level deletes or MERGE operations on legacy v1 tables; migrating writers but not the table format; misconfigured table creation defaulting to v1.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot read files that require applying delete files
- Cannot write manifest for table version: %s
- Deletes are supported in V2 and above
- Unknown delete file content:
- Can't retrieve values from an empty struct
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d9eae2648fd2e000.
Report an issue: GitHub.