prestodb/presto · error · PrestoException

ALREADY_EXISTS

ALREADY_EXISTS

Error message

TableFuncitonProcessorProvider already exists for connectorId %s. Overwriting is not supported.

What it means

Presto allows at most one TableFunctionProcessorProvider per connector. addTableFunctionProcessorProvider uses putIfAbsent and throws ALREADY_EXISTS if a provider was already registered for the given ConnectorId, because silently overwriting provider state is not supported.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/metadata/FunctionAndTypeManager.java:741

        }
        if (isBuiltInWorkerFunctionHandle(functionHandle)) {
            return builtInWorkerFunctionNamespaceManager.getScalarFunctionImplementation(functionHandle);
        }

        Optional<FunctionNamespaceManager<?>> functionNamespaceManager = getServingFunctionNamespaceManager(functionHandle.getCatalogSchemaName());
        checkArgument(functionNamespaceManager.isPresent(), "Cannot find function namespace for '%s'", functionHandle.getCatalogSchemaName());
        return functionNamespaceManager.get().getScalarFunctionImplementation(functionHandle);
    }

    public TableFunctionProcessorProvider getTableFunctionProcessorProvider(TableFunctionHandle tableFunctionHandle)
    {
        return tableFunctionProcessorProviderMap.get(tableFunctionHandle.getConnectorId()).apply(tableFunctionHandle.getFunctionHandle());
    }

    public void addTableFunctionProcessorProvider(ConnectorId connectorId, Function<ConnectorTableFunctionHandle, TableFunctionProcessorProvider> tableFunctionProcessorProvider)
    {
        if (tableFunctionProcessorProviderMap.putIfAbsent(connectorId, tableFunctionProcessorProvider) != null) {
            throw new PrestoException(ALREADY_EXISTS,
                    format("TableFuncitonProcessorProvider already exists for connectorId %s. Overwriting is not supported.", connectorId.getCatalogName()));
        }
    }

    public void removeTableFunctionProcessorProvider(ConnectorId connectorId)
    {
        tableFunctionProcessorProviderMap.remove(connectorId);
    }

    public AggregationFunctionImplementation getAggregateFunctionImplementation(FunctionHandle functionHandle)
    {
        if (isBuiltInPluginFunctionHandle(functionHandle)) {
            return builtInPluginFunctionNamespaceManager.getAggregateFunctionImplementation(functionHandle, this);
        }
        if (isBuiltInWorkerFunctionHandle(functionHandle)) {
            return builtInWorkerFunctionNamespaceManager.getAggregateFunctionImplementation(functionHandle, this);
        }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Call removeTableFunctionProcessorProvider(connectorId) before adding the new provider
  2. Guard registration with a check so the provider is added only once per connectorId
  3. Fix the plugin lifecycle so registration happens exactly once (e.g. in class-load/init, not per-connection)
  4. If the old provider must be replaced, remove then re-add rather than expecting overwrite

Example fix

// before
functionAndTypeManager.addTableFunctionProcessorProvider(connectorId, provider);
functionAndTypeManager.addTableFunctionProcessorProvider(connectorId, newProvider); // throws ALREADY_EXISTS
// after
functionAndTypeManager.removeTableFunctionProcessorProvider(connectorId);
functionAndTypeManager.addTableFunctionProcessorProvider(connectorId, newProvider);
Defensive patterns

Strategy: validation

Validate before calling

if (providerRegisteredFor(connectorId)) { skipOrRemoveFirst(); }

Try / catch

try { fam.addTableFunctionProcessorProvider(connectorId, p); } catch (PrestoException e) { if (e.getErrorCode() == ALREADY_EXISTS) { fam.removeTableFunctionProcessorProvider(connectorId); fam.addTableFunctionProcessorProvider(connectorId, p); } }

Prevention

When it happens

Trigger: Calling FunctionAndTypeManager.addTableFunctionProcessorProvider(connectorId, provider) twice for the same connector without calling removeTableFunctionProcessorProvider in between; typically a plugin or connector trying to re-register during reconfiguration or test setup.

Common situations: Connector plugin lifecycle bugs where the connector is activated twice; unit tests that rebuild the FunctionAndTypeManager or re-add providers against the same instance; hot-swapping a connector's table function provider without removal.

Related errors


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