{"record":{"id":"f22f9b200b0784cd","repo":"chinabugotech/hutool","slug":"illegal-pattern-component","errorCode":null,"errorMessage":"Illegal pattern component: {}","messagePattern":"Illegal pattern component: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java","lineNumber":202,"sourceCode":"\t\t\t\tcase 'Z': // time zone (value)\n\t\t\t\t\tif (tokenLen == 1) {\n\t\t\t\t\t\trule = TimeZoneNumberRule.INSTANCE_NO_COLON;\n\t\t\t\t\t} else if (tokenLen == 2) {\n\t\t\t\t\t\trule = Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;\n\t\t\t\t\t} else {\n\t\t\t\t\t\trule = TimeZoneNumberRule.INSTANCE_COLON;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\'': // literal text\n\t\t\t\t\tfinal String sub = token.substring(1);\n\t\t\t\t\tif (sub.length() == 1) {\n\t\t\t\t\t\trule = new CharacterLiteral(sub.charAt(0));\n\t\t\t\t\t} else {\n\t\t\t\t\t\trule = new StringLiteral(sub);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new IllegalArgumentException(\"Illegal pattern component: \" + token);\n\t\t\t}\n\n\t\t\trules.add(rule);\n\t\t}\n\n\t\treturn rules;\n\t}\n\n\t/**\n\t * <p>\n\t * Performs the parsing of tokens.\n\t * </p>\n\t *\n\t * @param pattern  the pattern\n\t * @param indexRef index references\n\t * @return parsed token\n\t */\n\tprotected String parseToken(String pattern, int[] indexRef) {","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java#L184-L220","documentation":"Thrown by FastDatePrinter while tokenizing a pattern: a token (pattern letter) was encountered that has no case in the format-rule switch, so it falls to the default branch. Unlike the parser, this occurs when building the printer (formatter) for a pattern whose leading letter is unsupported.","triggerScenarios":"Constructing a FastDateFormat/DateUtil.format pattern that begins with an unsupported pattern letter; stray characters that survive tokenization (e.g. a non-escaped letter). The offending token string is included.","commonSituations":"Patterns with letters Hutool's printer does not implement; copying patterns from other libraries; accidental letters that are not wrapped in quotes.","solutions":["Inspect the reported token and replace it with a supported pattern letter.","Wrap any literal alphabetic text in single quotes so it is treated as a literal, not a token.","Cross-check the letter against FastDatePrinter's switch cases (y,M,d,H,m,s,S,E,u,D,F,w,W,a,k,K,X,z,Z)."],"exampleFix":"// before (unknown token)\nFastDateFormat fdf = FastDateFormat.getInstance(\"yyyy-MM-dd 'at' T\");\n// after (escape literal letters, use real tokens)\nFastDateFormat fdf = FastDateFormat.getInstance(\"yyyy-MM-dd 'at' HH:mm\");","handlingStrategy":"validation","validationCode":"void assertPrintable(String p){\n  // quick guard: any unquoted alphabetic token must be a known printer letter\n  Set<Character> ok = Set.of('y','M','d','H','k','K','h','m','s','S','E','u','D','F','w','W','a','G','z','Z','X');\n  boolean inQuote=false;\n  for(int i=0;i<p.length();i++){ char c=p.charAt(i); if(c=='\\''){ inQuote=!inQuote; continue;} if(!inQuote && Character.isLetter(c) && !ok.contains(c)) throw new IllegalArgumentException(\"illegal token \"+c); }\n}","typeGuard":null,"tryCatchPattern":"try { FastDateFormat.getInstance(pattern); }\ncatch (IllegalArgumentException e){ if(e.getMessage().startsWith(\"Illegal pattern component\")) { /* fix token */ } else throw e; }","preventionTips":["Escape literal alphabetic text in single quotes.","Centralize format strings as constants.","Test formatter construction at startup."],"tags":["date","format-pattern","formatting","fast-date","argument"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}