{"record":{"id":"52891de0907a64dd","repo":"alibaba/spring-ai-alibaba","slug":"not-a-wrapper-for-interface-name","errorCode":null,"errorMessage":"Not a wrapper for <interface name>","messagePattern":"Not a wrapper for <interface name>","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java","lineNumber":646,"sourceCode":"\t\t\tthis.loginTimeout = seconds;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getLoginTimeout() {\n\t\t\treturn loginTimeout;\n\t\t}\n\n\t\t@Override\n\t\tpublic Logger getParentLogger() throws SQLFeatureNotSupportedException {\n\t\t\tthrow new SQLFeatureNotSupportedException();\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> T unwrap(Class<T> iface) throws SQLException {\n\t\t\tif (iface.isInstance(this)) {\n\t\t\t\treturn iface.cast(this);\n\t\t\t}\n\t\t\tthrow new SQLException(\"Not a wrapper for \" + iface.getName());\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isWrapperFor(Class<?> iface) {\n\t\t\treturn iface.isInstance(this);\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":628,"sourceCodeEnd":657,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java#L628-L657","documentation":"The Connection wrapper used by H2Saver implements the JDBC Wrapper pattern: unwrap(Class<T>) returns this only if iface.isInstance(this) (i.e. the requested interface is implemented by the wrapper itself), otherwise it throws SQLException(\"Not a wrapper for <interface name>\"). Unlike delegating wrappers, it cannot unwrap the underlying driver Connection.","triggerScenarios":"Calling conn.unwrap(SomeDriverConnectionClass.class) — or isWrapperFor-driven unwrap of a native H2/driver connection interface — on the saver's wrapper connection when the wrapper does not implement that interface.","commonSituations":"Driver-specific code (e.g. accessing H2's JdbcConnection for vendor features) or pooling/proxy frameworks trying to unwrap the native connection and hitting the wrapper instead.","solutions":["Check isWrapperFor(iface) before calling unwrap and fall back if false.","Obtain the underlying native connection directly from the DataSource instead of unwrapping through the saver's wrapper.","If vendor-specific features are needed, bypass the saver's connection wrapper and use your own connection to the same H2 database.","Catch SQLException with message prefix 'Not a wrapper for' and handle gracefully."],"exampleFix":"// before: blind unwrap throws\nJdbcConnection h2 = conn.unwrap(JdbcConnection.class); // SQLException\n// after: guard first\nif (conn.isWrapperFor(JdbcConnection.class)) {\n  JdbcConnection h2 = conn.unwrap(JdbcConnection.class);\n} else { /* use generic JDBC API */ }","handlingStrategy":"type-guard","validationCode":"if (!conn.isWrapperFor(TargetConnection.class)) { /* use generic JDBC API instead */ }","typeGuard":"boolean unwrappable(Connection c, Class<?> iface) { return c.isWrapperFor(iface); }","tryCatchPattern":"try { return conn.unwrap(TargetConnection.class); }\ncatch (SQLException e) { if (e.getMessage().startsWith(\"Not a wrapper for\")) return null; throw e; }","preventionTips":["Always call isWrapperFor before unwrap","Avoid vendor-specific connection casts through the saver's wrapper","Get a separate native connection from the DataSource for driver-specific features"],"tags":["jdbc","unwrap","h2","wrapper"],"backgroundTag":"unsupported-operation","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}