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

  1. Set session insert_existing_partitions_behavior=OVERWRITE if the intent is to replace partition contents
  2. Use INSERT with a filter excluding already-present partitions, or delete/drop the existing partition before inserting
  3. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/a38425b9b126c235. Report an issue: GitHub.