{"record":{"id":"e8b5cfb2e4c157ff","repo":"prestodb/presto","slug":"generic-internal-error-e8b5cf","errorCode":"GENERIC_INTERNAL_ERROR","errorMessage":"ConnectorMetadata getCommonPartitioningHandle() is implemented without getAlternativeLayout()","messagePattern":"ConnectorMetadata getCommonPartitioningHandle\\(\\) is implemented without getAlternativeLayout\\(\\)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"critical","filePath":"presto-spi/src/main/java/com/facebook/presto/spi/connector/ConnectorMetadata.java","lineNumber":185,"sourceCode":"        }\n        else if (layouts.size() > 1) {\n            throw new PrestoException(NOT_SUPPORTED, \"Connector returned multiple layouts for table \" + table);\n        }\n        return layouts.get(0);\n    }\n\n    ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTableLayoutHandle handle);\n\n    /**\n     * Return a table layout handle whose partitioning is converted to the provided partitioning handle,\n     * but otherwise identical to the provided table layout handle.\n     * The provided table layout handle must be one that the connector can transparently convert to from\n     * the original partitioning handle associated with the provided table layout handle,\n     * as promised by {@link #getCommonPartitioningHandle}.\n     */\n    default ConnectorTableLayoutHandle getAlternativeLayoutHandle(ConnectorSession session, ConnectorTableLayoutHandle tableLayoutHandle, ConnectorPartitioningHandle partitioningHandle)\n    {\n        throw new PrestoException(GENERIC_INTERNAL_ERROR, \"ConnectorMetadata getCommonPartitioningHandle() is implemented without getAlternativeLayout()\");\n    }\n\n    /**\n     * Experimental: if true, the engine will invoke getLayout otherwise, getLayout will not be called.\n     */\n    @Deprecated\n    @Experimental\n    default boolean isLegacyGetLayoutSupported(ConnectorSession session, ConnectorTableHandle tableHandle)\n    {\n        return true;\n    }\n\n    /**\n     * Return a partitioning handle which the connector can transparently convert both {@code left} and {@code right} into.\n     */\n    @Deprecated\n    default Optional<ConnectorPartitioningHandle> getCommonPartitioningHandle(ConnectorSession session, ConnectorPartitioningHandle left, ConnectorPartitioningHandle right)\n    {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-spi/src/main/java/com/facebook/presto/spi/connector/ConnectorMetadata.java#L167-L203","documentation":"getAlternativeLayoutHandle() defaults to throwing GENERIC_INTERNAL_ERROR with this message. The contract is that if a connector implements getCommonPartitioningHandle() (promising it can transparently convert layout handles to a common partitioning), it must also implement getAlternativeLayoutHandle(). Hitting the default means the connector broke that contract, so the engine reports it as an internal error.","triggerScenarios":"The engine's newTableLayoutHandle path calls getAlternativeLayoutHandle on a connector that implements getCommonPartitioningHandle but not getAlternativeLayoutHandle; the default throws GENERIC_INTERNAL_ERROR.","commonSituations":"Custom connector development where getCommonPartitioningHandle was implemented (e.g. for CTE/writer repartitioning) but the companion getAlternativeLayoutHandle was forgotten; upgrading a connector partially.","solutions":["Implement getAlternativeLayoutHandle(ConnectorSession, ConnectorTableLayoutHandle, ConnectorPartitioningHandle) in the connector to translate the layout handle to the common partitioning","If the connector cannot actually convert handles, remove/fix the getCommonPartitioningHandle implementation so it no longer promises common partitioning","Report as a connector bug if using a third-party connector"],"exampleFix":"// before: only getCommonPartitioningHandle overridden\n// after\n@Override\npublic ConnectorTableLayoutHandle getAlternativeLayoutHandle(ConnectorSession session, ConnectorTableLayoutHandle handle, ConnectorPartitioningHandle partitioningHandle) {\n    return ((MyLayoutHandle) handle).withPartitioning((MyPartitioningHandle) partitioningHandle);\n}","handlingStrategy":"validation","validationCode":"// connector self-check: the pair must be implemented together\n@Override\npublic ConnectorPartitioningHandle getCommonPartitioningHandle(ConnectorSession session, ConnectorPartitioningHandle left, ConnectorPartitioningHandle right) {\n    if (getClass().getMethod(\"getAlternativeLayoutHandle\", ConnectorSession.class, ConnectorTableLayoutHandle.class, ConnectorPartitioningHandle.class)\n            .getDeclaringClass() == ConnectorMetadata.class) {\n        throw new IllegalStateException(\"getCommonPartitioningHandle requires getAlternativeLayoutHandle\");\n    }\n    return super.getCommonPartitioningHandle(session, left, right);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return metadata.getAlternativeLayoutHandle(session, layoutHandle, partitioningHandle);\n} catch (PrestoException e) {\n    if (e.getErrorCode() == StandardErrorCode.GENERIC_INTERNAL_ERROR.toErrorCodeCode()) {\n        throw new IllegalStateException(\"Connector contract violation: getCommonPartitioningHandle without getAlternativeLayoutHandle\", e);\n    }\n    throw e;\n}","preventionTips":["Whenever implementing getCommonPartitioningHandle, implement getAlternativeLayoutHandle in the same change","Add a connector unit test exercising the alternative-layout path","Review connector upgrades for partially implemented partitioning contracts"],"tags":["presto","connector","internal-error","partitioning","contract-violation"],"backgroundTag":"connector-contract-violation","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}