alibaba/spring-ai-alibaba · error · SQLException

Not a wrapper for

Error message

Not a wrapper for <interface name>

What it means

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.

Solutions

  1. Check isWrapperFor(iface) before calling unwrap and fall back if false.
  2. Obtain the underlying native connection directly from the DataSource instead of unwrapping through the saver's wrapper.
  3. If vendor-specific features are needed, bypass the saver's connection wrapper and use your own connection to the same H2 database.
  4. Catch SQLException with message prefix 'Not a wrapper for' and handle gracefully.

Example fix

// before: blind unwrap throws
JdbcConnection h2 = conn.unwrap(JdbcConnection.class); // SQLException
// after: guard first
if (conn.isWrapperFor(JdbcConnection.class)) {
  JdbcConnection h2 = conn.unwrap(JdbcConnection.class);
} else { /* use generic JDBC API */ }
Defensive patterns

Strategy: type-guard

Validate before calling

if (!conn.isWrapperFor(TargetConnection.class)) { /* use generic JDBC API instead */ }

Type guard

boolean unwrappable(Connection c, Class<?> iface) { return c.isWrapperFor(iface); }

Try / catch

try { return conn.unwrap(TargetConnection.class); }
catch (SQLException e) { if (e.getMessage().startsWith("Not a wrapper for")) return null; throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/52891de0907a64dd. Report an issue: GitHub.

Appendix: source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java:646

			this.loginTimeout = seconds;
		}

		@Override
		public int getLoginTimeout() {
			return loginTimeout;
		}

		@Override
		public Logger getParentLogger() throws SQLFeatureNotSupportedException {
			throw new SQLFeatureNotSupportedException();
		}

		@Override
		public <T> T unwrap(Class<T> iface) throws SQLException {
			if (iface.isInstance(this)) {
				return iface.cast(this);
			}
			throw new SQLException("Not a wrapper for " + iface.getName());
		}

		@Override
		public boolean isWrapperFor(Class<?> iface) {
			return iface.isInstance(this);
		}

	}

}

View on GitHub (pinned to f82da0b50f)