OtterMind/Chat2DB · error · IllegalArgumentException
Unsafe {what} name: {name}
Error message
Unsafe {what} name: {name} What it means
Thrown by SqliteSqlGuards.requireSafeName when a name destined for a non-escapable keyword position (collation/charset) is null or does not fully match the allow-list regex [A-Za-z0-9_]+. Because these names cannot be quoted/escaped, anything outside ASCII alphanumerics and underscore is rejected to prevent DDL injection (fail closed).
Source
Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-sqlite/src/main/java/ai/chat2db/plugin/sqlite/SqliteSqlGuards.java:53
"AUTOINCREMENT", "CHECK", "COLLATE", "CONSTRAINT", "DEFAULT", "GENERATED",
"NOT", "NULL", "PRIMARY", "REFERENCES", "UNIQUE");
private static final Set<String> STATEMENT_KEYWORDS = Set.of(
"ALTER", "ATTACH", "CREATE", "DELETE", "DETACH", "DROP", "INSERT", "PRAGMA",
"REINDEX", "REPLACE", "SELECT", "UPDATE", "VACUUM");
private SqliteSqlGuards() {
}
/**
* Validates a name embedded into a keyword position (collation, charset) against a
* conservative allow-list. Returns the name unchanged when safe; throws otherwise
* (fail closed).
*
* @throws IllegalArgumentException if the name contains unexpected characters
*/
public static String requireSafeName(String name, String what) {
if (name == null || !SAFE_NAME.matcher(name).matches()) {
throw new IllegalArgumentException("Unsafe " + what + " name: " + name);
}
return name;
}
/**
* Validates a free-text column type name before it is embedded into generated DDL.
* Returns the type name unchanged when it matches a conservative allow-list;
* throws otherwise (fail closed).
*
* @throws IllegalArgumentException if the type name contains unexpected characters
*/
public static String requireSafeTypeName(String typeName) {
String expression = StringUtils.trimToNull(typeName);
if (expression == null) {
return null;
}
scanExpression(expression, true, "column type");
return expression;View on GitHub (pinned to 5ee1e990e7)
Solutions
- Trim and restrict the name to ASCII letters, digits, and underscore.
- Pre-validate with the same [A-Za-z0-9_]+ pattern before calling the DDL builder.
- If a genuinely exotic collation name is required, register/handle it through a quoted path rather than the keyword-position path.
Example fix
// before
column.setCollationName("zh phonebook"); // space not allowed
// after
column.setCollationName("zh_phonebook"); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check the same allow-list the guard uses
private static final java.util.regex.Pattern SAFE = java.util.regex.Pattern.compile("[A-Za-z0-9_]+");
if (name != null && !SAFE.matcher(name).matches()) {
throw new IllegalArgumentException("Name fails allow-list: " + name);
} Type guard
static boolean isSafeSqliteName(String name) {
return name != null && name.matches("[A-Za-z0-9_]+");
} Prevention
- Trim and restrict collation/charset names to ASCII alphanumerics and underscore.
- Validate at the boundary with the same regex before DDL generation.
- Treat null names as 'omit the clause' rather than forwarding them.
When it happens
Trigger: Passing a collation or charset name containing spaces, dots, parentheses, quotes, or any non-[A-Za-z0-9_] character (e.g. 'NOCASE' is fine, but 'BINARY' with a trailing space, or a localized/custom collation like 'zh_phonebook' is fine whereas 'zh phonebook' is not). A null name also triggers it.
Common situations: User-typed or metadata-supplied collation with whitespace/punctuation; copy-paste introducing a stray character; a custom collation whose name contains a hyphen.
Related errors
- Invalid SQL Server collation name: {collation}
- SQLite index must contain at least one named column
- Invalid SUNDB index sort direction: {value}
- Unsupported VARCHAR unit: {unit}
- web.not.support.db.type
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/d9f896ff6fe493e4.
Report an issue: GitHub.