prestodb/presto · error · PrestoException

HIVE_CONCURRENT_MODIFICATION_DETECTED

HIVE_CONCURRENT_MODIFICATION_DETECTED

Error message

Table format changed during insert

What it means

Presto detected that the target table's storage format (input format) changed between the moment the INSERT statement began and when metadata was being finalized. Because the session honors the table format (respect-table-format), the earlier-captured format is stale, and continuing could write files in the wrong format. Presto throws HIVE_CONCURRENT_MODIFICATION_DETECTED to abort safely.

Source

Thrown at presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java:2218

    {
        return finishInsertInternal(session, insertHandle, fragments, computedStatistics);
    }

    private Optional<ConnectorOutputMetadata> finishInsertInternal(ConnectorSession session, ConnectorInsertTableHandle insertHandle, Collection<Slice> fragments, Collection<ComputedStatistics> computedStatistics)
    {
        HiveInsertTableHandle handle = (HiveInsertTableHandle) insertHandle;

        List<PartitionUpdate> partitionUpdates = getPartitionUpdates(session, fragments);

        HiveStorageFormat tableStorageFormat = handle.getTableStorageFormat();
        partitionUpdates = PartitionUpdate.mergePartitionUpdates(partitionUpdates);

        MetastoreContext metastoreContext = getMetastoreContext(session);

        Table table = metastore.getTable(metastoreContext, handle.getSchemaName(), handle.getTableName())
                .orElseThrow(() -> new TableNotFoundException(handle.getSchemaTableName()));
        if (!table.getStorage().getStorageFormat().getInputFormat().equals(tableStorageFormat.getInputFormat()) && isRespectTableFormat(session)) {
            throw new PrestoException(HIVE_CONCURRENT_MODIFICATION_DETECTED, "Table format changed during insert");
        }

        if (handle.getBucketProperty().isPresent() && isCreateEmptyBucketFiles(session)) {
            List<PartitionUpdate> partitionUpdatesForMissingBuckets = computePartitionUpdatesForMissingBuckets(
                    session,
                    handle,
                    table,
                    partitionUpdates);
            // replace partitionUpdates before creating the zero-row files so that those files will be cleaned up if we end up rollback
            partitionUpdates = PartitionUpdate.mergePartitionUpdates(concat(partitionUpdates, partitionUpdatesForMissingBuckets));
            HdfsContext hdfsContext = new HdfsContext(session, table.getDatabaseName(), table.getTableName(), table.getStorage().getLocation(), false);
            for (PartitionUpdate partitionUpdate : partitionUpdatesForMissingBuckets) {
                Optional<Partition> partition = table.getPartitionColumns().isEmpty() ? Optional.empty() :
                        Optional.of(partitionObjectBuilder.buildPartitionObject(
                                session,
                                table,
                                partitionUpdate,
                                prestoVersion,

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Rerun the INSERT after the concurrent ALTER completes; the retry will see the new format
  2. Coordinate format-change DDL so it runs outside ETL windows (job scheduling/mutual exclusion)
  3. If intentional and acceptable, set session respect_table_format=false so writes use the session format (verify this is actually desired)
Defensive patterns

Strategy: retry

Validate before calling

// Before finalizing: re-read the table and compare input formats
Table current = metastore.getTable(ctx, schema, table).orElseThrow();
if (!current.getStorage().getStorageFormat().getInputFormat()
        .equals(expectedFormat.getInputFormat())) {
    throw new IllegalStateException("Format changed concurrently; rerun insert");
}

Try / catch

try {
    session.execute("INSERT INTO target SELECT ...");
} catch (PrestoException e) {
    if (e.getErrorCode().getCode() == HIVE_CONCURRENT_MODIFICATION_DETECTED.getCode()) {
        // safe to retry: re-plan sees the new table format
    } else { throw e; }
}

Prevention

When it happens

Trigger: A concurrent ALTER TABLE ... SET FILEFORMAT / SET TABLE PROPERTIES (storage format change) or a table replacement happened while an INSERT into that table was in progress, checked in finishInsert when respect_table_format is enabled.

Common situations: Migration scripts running format conversions (e.g. TextFile to ORC) concurrently with ETL INSERT jobs on the same table.

Related errors


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