prestodb/presto · error · PrestoException
HIVE_PARTITION_READ_ONLY
HIVE_PARTITION_READ_ONLY
Error message
Cannot insert into an existing partition of Hive table:
What it means
The INSERT plan requires overwriting an existing partition, but the resolved update path for that partition is neither a supported overwrite (which would drop/recreate the partition) nor a new partition; the partition exists and Presto refuses to write into it. HIVE_PARTITION_READ_ONLY signals the existing partition is effectively read-only for this insert — typically because the behavior is ERROR or the write mode cannot drop the existing partition.
Source
Thrown at presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java:2336
getManifestSizeInBytes(session, partitionUpdate, extraPartitionMetadata).ifPresent(hivePartitionStats::addManifestSizeInBytes);
boolean isExistingPartition = existingPartitions.containsKey(partitionUpdate.getName());
Optional<Partition> existingPartition = Optional.empty();
if (isExistingPartition) {
// Overwriting an existing partition
if (partitionUpdate.getUpdateMode() == OVERWRITE) {
existingPartition = existingPartitions.get(partitionUpdate.getName());
if (handle.getLocationHandle().getWriteMode() == DIRECT_TO_TARGET_EXISTING_DIRECTORY) {
// In this writeMode, the new files will be written to the same directory. Since this is
// an overwrite operation, we must remove all the old files not written by current query.
removeNonCurrentQueryFiles(session, partitionUpdate.getTargetPath());
}
else {
metastore.dropPartition(session, handle.getSchemaName(), handle.getTableName(), handle.getLocationHandle().getTargetPath().toString(), extractPartitionValues(partitionUpdate.getName()));
}
}
else {
throw new PrestoException(HIVE_PARTITION_READ_ONLY, "Cannot insert into an existing partition of Hive table: " + partitionUpdate.getName());
}
}
// insert into new partition or overwrite existing partition
Partition partition = partitionObjectBuilder.buildPartitionObject(
session,
table,
partitionUpdate,
prestoVersion,
extraPartitionMetadata,
existingPartition,
Optional.empty());
if (!partition.getStorage().getStorageFormat().getInputFormat().equals(handle.getPartitionStorageFormat().getInputFormat()) && isRespectTableFormat(session)) {
throw new PrestoException(HIVE_CONCURRENT_MODIFICATION_DETECTED, "Partition format changed during insert");
}
String partitionName = partitionUpdate.getName();
List<String> partitionValues = partition.getValues();
List<Type> partitionTypes = partitionedBy.stream()View on GitHub (pinned to 55bb57d202)
Solutions
- Set session insert_existing_partitions_behavior=OVERWRITE if the intent is to replace partition contents
- Use INSERT with a filter excluding already-present partitions, or delete/drop the existing partition before inserting
- If the partition is managed externally, load via a new partition (distinct value set) or use Hive to manage the overwrite
Example fix
// before INSERT INTO events PARTITION (ds='2026-09-01') SELECT ... ; -- partition exists, behavior=ERROR // after SET SESSION hive.insert_existing_partitions_behavior = 'OVERWRITE'; INSERT INTO events PARTITION (ds='2026-09-01') SELECT ...;
Defensive patterns
Strategy: validation
Validate before calling
// Before INSERT: check whether target partitions already exist
List<String> existing = existingPartitionNames(metastore, ctx, schema, name, plannedPartitions);
if (!existing.isEmpty()
&& "ERROR".equals(session.getProperty("insert_existing_partitions_behavior"))) {
throw new IllegalStateException("Existing partitions would block INSERT: " + existing);
} Try / catch
try {
session.execute("INSERT INTO events PARTITION (ds='...') SELECT ...");
} catch (PrestoException e) {
if ("HIVE_PARTITION_READ_ONLY".equals(e.getErrorCode().getName())) {
// drop the partition or set OVERWRITE behavior, then retry
} else { throw e; }
} Prevention
- Pre-check existing partitions in ETL before inserting
- Adopt a consistent insert_existing_partitions_behavior per pipeline
- Use idempotent partition keys so reruns overwrite rather than collide
When it happens
Trigger: INSERT with insert_existing_partitions_behavior=ERROR (default) hitting a partition that already exists; or a write mode (e.g. DIRECT_TO_TARGET_EXISTING_DIRECTORY precheck) that does not drop the partition, in the else-branch of the partition update loop in finishInsert.
Common situations: Repeated ETL runs re-inserting the same day's partition with the default ERROR behavior; backfills targeting partitions already loaded by another job.
Related errors
- HIVE_CONCURRENT_MODIFICATION_DETECTED
- HIVE_FILESYSTEM_ERROR
- HIVE_CONCURRENT_MODIFICATION_DETECTED
- Inserting into an unpartitioned table that were added, alter
- NOT_SUPPORTED
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/a38425b9b126c235.
Report an issue: GitHub.