{"record":{"id":"30b6dec23857d7f8","repo":"OtterMind/Chat2DB","slug":"invalid-snowflake-what-value","errorCode":null,"errorMessage":"Invalid Snowflake {what}: {value}","messagePattern":"Invalid Snowflake (.+?): (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-snowflake/src/main/java/ai/chat2db/plugin/snowflake/SnowflakeSqlGuards.java","lineNumber":40,"sourceCode":"            \"GRANT\", \"INSERT\", \"MERGE\", \"PRIMARY\", \"REFERENCES\", \"REVOKE\", \"TRUNCATE\", \"UNIQUE\",\n            \"UPDATE\", \"SELECT\");\n    private static final Set<String> TYPE_BREAKOUT_KEYWORDS = Set.of(\n            \"CHECK\", \"COLLATE\", \"CONSTRAINT\", \"DEFAULT\", \"GENERATED\", \"NOT\", \"NULL\", \"PRIMARY\",\n            \"REFERENCES\", \"UNIQUE\");\n    private static final Set<String> CLAUSE_BREAKOUT_KEYWORDS = Set.of(\n            \"ALTER\", \"CALL\", \"COPY\", \"CREATE\", \"DELETE\", \"DROP\", \"GRANT\", \"INSERT\", \"MERGE\",\n            \"REVOKE\", \"TRUNCATE\", \"UPDATE\", \"USE\");\n\n    private SnowflakeSqlGuards() {\n    }\n\n    /**\n     * Validate a strict Snowflake name token (ENGINE / CHARACTER SET / COLLATE style positions where\n     * escaping is impossible by design).\n     */\n    public static String requireSnowflakeName(String value, String what) {\n        if (value == null || !SNOWFLAKE_NAME_PATTERN.matcher(value).matches()) {\n            throw new IllegalArgumentException(\"Invalid Snowflake \" + what + \": \" + value);\n        }\n        return value;\n    }\n\n    /**\n     * Validate a quote-aware DEFAULT expression. Quoted literal content is normalized without\n     * double-escaping existing doubled quotes. Other expressions may contain nested calls and\n     * Snowflake sequence references, but cannot terminate the statement or append a constraint.\n     */\n    public static String requireDefaultExpression(String value) {\n        if (StringUtils.isBlank(value)) {\n            throw invalid(\"default value\", value);\n        }\n        String trimmed = value.trim();\n        if (trimmed.length() >= 2 && trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n            return \"'\" + normalizeStringLiteralContent(trimmed.substring(1, trimmed.length() - 1)) + \"'\";\n        }\n        scanExpression(trimmed, DEFAULT_BREAKOUT_KEYWORDS, false, \"default value\");","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-snowflake/src/main/java/ai/chat2db/plugin/snowflake/SnowflakeSqlGuards.java#L22-L58","documentation":"Thrown by SnowflakeSqlGuards.requireSnowflakeName when the value is null or does not match the pattern ^[A-Za-z0-9_$]+$. This validates strict name tokens used in positions where identifier quoting is impossible by design (ENGINE, CHARACTER SET, COLLATE). Only unquoted alphanumeric, underscore, and dollar-sign characters are accepted. The 'what' parameter labels which name type failed (e.g., engine, character set, collation).","triggerScenarios":"Calling SnowflakeSqlGuards.requireSnowflakeName(value, what) where value is null, empty, or contains characters outside [A-Za-z0-9_$]. This includes spaces, hyphens, dots, special characters, and non-ASCII characters.","commonSituations":"A column or table metadata field containing a space or special character in an engine/charset/collation position; a user-entered default value referencing an object name with invalid characters; metadata imported from a system that allows characters Snowflake rejects in unquoted positions.","solutions":["Sanitize the name to contain only [A-Za-z0-9_$] characters before calling requireSnowflakeName","Quote the identifier at the SQL construction level instead of passing it through this strict guard","Validate user input against the same pattern before submitting DDL"],"exampleFix":"// before\nSnowflakeSqlGuards.requireSnowflakeName(\"my engine\", \"engine\");\n\n// after\nString name = \"my_engine\"; // sanitize: replace spaces/special chars with underscore\nSnowflakeSqlGuards.requireSnowflakeName(name, \"engine\");","handlingStrategy":"validation","validationCode":"private static final Pattern SNOWFLAKE_NAME = Pattern.compile(\"^[A-Za-z0-9_$]+$\");\n\npublic static String sanitizeSnowflakeName(String value) {\n    if (value == null || !SNOWFLAKE_NAME.matcher(value).matches()) {\n        String sanitized = value == null ? \"\" : value.replaceAll(\"[^A-Za-z0-9_$]\", \"_\");\n        return sanitized.isEmpty() ? null : sanitized;\n    }\n    return value;\n}","typeGuard":"public static boolean isValidSnowflakeName(String value) {\n    return value != null && !value.isEmpty()\n        && value.chars().allMatch(c -> Character.isLetterOrDigit(c) || c == '_' || c == '$');\n}","tryCatchPattern":null,"preventionTips":["Validate names against ^[A-Za-z0-9_$]+$ before passing to requireSnowflakeName","Replace spaces and special characters with underscores as a sanitization step","Use quoted identifiers at the SQL level instead of strict guards for names that need special characters"],"tags":["snowflake","ddl","validation","identifier","sql-injection"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}