OtterMind/Chat2DB · error · IllegalArgumentException
Unsafe column type name from metadata: {typeName}
Error message
Unsafe column type name from metadata: {typeName} What it means
Thrown by H2SqlGuards.requireSafeTypeName when a non-null JDBC metadata column type name does not match the allow-list ^[A-Za-z][A-Za-z0-9_]*(\s+[A-Za-z][A-Za-z0-9_]*)*$. The guard prevents hostile or corrupt metadata from injecting SQL into generated DDL; null is permitted and returned unchanged.
Source
Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-h2/src/main/java/ai/chat2db/plugin/h2/H2SqlGuards.java:50
"(?i)^(?:NOW|RANDOM_UUID|UUID)\\(\\s*(?:\\d+)?\\s*\\)$");
private static final Pattern TYPED_LITERAL = Pattern.compile(
"(?i)^(?:DATE|TIME(?:\\s+WITH\\s+TIME\\s+ZONE)?|TIMESTAMP(?:\\s+WITH\\s+TIME\\s+ZONE)?|UUID|JSON|GEOMETRY)\\s+"
+ STRING_LITERAL_SOURCE + "$");
private static final Pattern BINARY_LITERAL = Pattern.compile("(?i)^(?:X|BINARY)\\s*'[0-9A-F]*'$");
private static final Pattern SEQUENCE_EXPRESSION = Pattern.compile(
"(?i)^NEXT\\s+VALUE\\s+FOR\\s+" + IDENTIFIER_SOURCE + "(?:\\." + IDENTIFIER_SOURCE + ")?$");
private H2SqlGuards() {
}
/**
* Validates a column type name obtained from JDBC metadata before it is embedded
* into generated DDL. Returns the type name unchanged when it matches the
* allow-list; throws otherwise (fail closed).
*/
public static String requireSafeTypeName(String typeName) {
if (typeName != null && !SAFE_TYPE_NAME.matcher(typeName).matches()) {
throw new IllegalArgumentException("Unsafe column type name from metadata: " + typeName);
}
return typeName;
}
/**
* Reconstructs a type declaration from JDBC metadata without treating display width as a
* type parameter. H2 reports values such as 64 for BIGINT and 26 for TIMESTAMP in
* COLUMN_SIZE, but those values are not legal declarations for these types.
*/
public static String renderMetadataType(String typeName, int dataType, int columnSize, int decimalDigits) {
String safeTypeName = requireSafeTypeName(typeName);
StringBuilder declaration = new StringBuilder(safeTypeName);
switch (dataType) {
case Types.CHAR:
case Types.VARCHAR:
case Types.NCHAR:
case Types.NVARCHAR:
case Types.BINARY:View on GitHub (pinned to 5ee1e990e7)
Solutions
- Strip type parameters before calling requireSafeTypeName; renderMetadataType appends size/precision itself from columnSize/decimalDigits.
- If the type name legitimately needs special characters, whitelist it explicitly or handle that column outside the metadata-driven path.
- Upgrade/verify the H2 driver returns a clean TYPE_NAME for the column.
Example fix
// before String t = "VARCHAR(255)"; // parentheses fail the allow-list H2SqlGuards.requireSafeTypeName(t); // after String t = "VARCHAR"; // base name only H2SqlGuards.renderMetadataType(t, Types.VARCHAR, 255, 0); // -> VARCHAR(255)
Defensive patterns
Strategy: validation
Validate before calling
private static final java.util.regex.Pattern SAFE_TYPE =
java.util.regex.Pattern.compile("^[A-Za-z][A-Za-z0-9_]*(?:\\s+[A-Za-z][A-Za-z0-9_]*)*$");
static boolean isSafeH2TypeName(String t) {
return t == null || SAFE_TYPE.matcher(t).matches();
} Type guard
static String h2BaseTypeName(String t) {
if (t == null) return null;
int p = t.indexOf('(');
return (p >= 0) ? t.substring(0, p).trim() : t; // caller renders params from metadata
} Prevention
- Pass only the base type name (no parentheses/params); renderMetadataType adds size/precision.
- Treat a rejected type name as a signal to inspect driver metadata, not to bypass the guard.
- Unit-test DDL round-trips against the H2 versions you support.
When it happens
Trigger: Calling requireSafeTypeName(typeName) or renderMetadataType(...) where typeName contains punctuation, digits-leading, parentheses, commas, or operators (e.g. "VARCHAR(255)", "INT,", "1TYPE"). Triggered when rebuilding a table DDL from H2 JDBC metadata that returns an unexpected TYPE_NAME.
Common situations: An H2 version or custom domain type whose TYPE_NAME includes parameter syntax; a corrupted metadata row; a column whose type name was manually edited to include size arguments.
Related errors
- Unsafe H2 column default from metadata: {columnDefault}
- Unsupported Kylin JDBC column type: {jdbcType}
- Invalid DB2 index column ordering: {ascOrDesc}
- Unsupported DM VARCHAR unit: {unit}
- Invalid DM index sort direction: {value}
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/abd644d533dff05b.
Report an issue: GitHub.