prestodb/presto · error · PrestoException

ICEBERG_INVALID_SPEC_ID

ICEBERG_INVALID_SPEC_ID

Error message

Given spec id does not exist: %s

What it means

RewriteManifestsProcedure accepts an optional specId parameter identifying which partition spec's manifests to rewrite. Before using it, the procedure verifies the id exists in the Iceberg table's specs() map. If not, it throws ICEBERG_INVALID_SPEC_ID because rewriting manifests against a non-existent spec would corrupt manifest metadata.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/procedure/RewriteManifestsProcedure.java:82

                "rewrite_manifests",
                ImmutableList.of(
                        new Argument("schema", VARCHAR),
                        new Argument("table_name", VARCHAR),
                        new Argument("spec_id", INTEGER, false, null)),
                REWRITE_MANIFESTS.bindTo(this));
    }

    public void rewriteManifests(ConnectorSession clientSession, String schemaName, String tableName, Integer specId)
    {
        try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(getClass().getClassLoader())) {
            SchemaTableName schemaTableName = new SchemaTableName(schemaName, tableName);
            IcebergAbstractMetadata metadata = (IcebergAbstractMetadata) metadataFactory.create();
            Table icebergTable = getIcebergTable(metadata, clientSession, schemaTableName);
            RewriteManifests rewriteManifests = icebergTable.rewriteManifests().clusterBy(file -> "file");
            int targetSpecId;
            if (specId != null) {
                if (!icebergTable.specs().containsKey(specId)) {
                    throw new PrestoException(ICEBERG_INVALID_SPEC_ID, "Given spec id does not exist: " + specId);
                }
                targetSpecId = specId;
            }
            else {
                targetSpecId = icebergTable.spec().specId();
            }
            rewriteManifests.rewriteIf(manifest -> manifest.partitionSpecId() == targetSpecId).commit();
            metadata.commit();
        }
    }
}

View on GitHub (pinned to 55bb57d202)

Solutions

  1. List the table's current spec ids (e.g. inspect the table metadata / specs) and pass an existing one
  2. Omit the spec_id argument so the procedure defaults to the table's current spec (icebergTable.spec().specId())
  3. If the spec was intentionally removed, rewrite manifests without spec_id and let Iceberg handle legacy specs

Example fix

// before
CALL system.rewrite_manifests(table => 'db.t', spec_id => 7); -- spec 7 no longer exists
// after
CALL system.rewrite_manifests(table => 'db.t'); -- uses current spec
Defensive patterns

Strategy: validation

Validate before calling

int specId = ...;
if (!icebergTable.specs().containsKey(specId)) {
    throw new IllegalArgumentException("Unknown spec id: " + specId +
        "; known ids: " + icebergTable.specs().keySet());
}

Type guard

boolean isValidSpecId(Table icebergTable, int specId) {
    return icebergTable.specs().containsKey(specId);
}

Try / catch

try {
    runRewriteManifests(specId);
} catch (PrestoException e) {
    if (ICEBERG_INVALID_SPEC_ID.equals(e.getErrorCode())) {
        // fall back to the table's current spec id
        runRewriteManifests(null);
    }
}

Prevention

When it happens

Trigger: CALL system.rewrite_manifests with spec_id => <n> where <n> is not a spec id of the target table — typically a stale or guessed id after the table's partition spec evolved (ids are monotonically assigned per spec change).

Common situations: Hard-coded spec_id from an earlier table version that was replaced via ALTER TABLE SET PROPERTIES; confusing spec_id with partition values or spec field ids; copying a spec id from a different table.

Related errors


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