chinabugotech/hutool · error · IllegalArgumentException

invalid number of X

Error message

invalid number of X

What it means

The ISO-8601 timezone token 'X' in a FastDateParser pattern only supports lengths 1, 2, or 3 (X, XX, XXX). Any other run length (e.g. XXXX or XXXXX) reaches the default branch and throws. Standard java.text.SimpleDateFormat allows 1-5 X's, so this is a reduced feature set.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java:775

		private static final Strategy ISO_8601_2_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
		private static final Strategy ISO_8601_3_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");

		/**
		 * Factory method for ISO8601TimeZoneStrategies.
		 *
		 * @param tokenLen a token indicating the length of the TimeZone String to be formatted.
		 * @return a ISO8601TimeZoneStrategy that can format TimeZone String of length {@code tokenLen}. If no such strategy exists, an IllegalArgumentException will be thrown.
		 */
		static Strategy getStrategy(final int tokenLen) {
			switch (tokenLen) {
				case 1:
					return ISO_8601_1_STRATEGY;
				case 2:
					return ISO_8601_2_STRATEGY;
				case 3:
					return ISO_8601_3_STRATEGY;
				default:
					throw new IllegalArgumentException("invalid number of X");
			}
		}
	}

	private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) {
		@Override
		int modify(final FastDateParser parser, final int iValue) {
			return iValue - 1;
		}
	};
	private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR);
	private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR);
	private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH);
	private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR);
	private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH);
	private static final Strategy DAY_OF_WEEK_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK) {
		@Override
		int modify(final FastDateParser parser, final int iValue) {

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Reduce the X run to at most 3 (XXX gives '+hh:mm' / 'Z').
  2. If XXXX/XXXXX semantics are needed, use java.text.SimpleDateFormat for that format instead of FastDateParser.
  3. Use Z or z tokens for zone formatting/parsing where appropriate.

Example fix

// before
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssXXXXX");
// after
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssXXX");
Defensive patterns

Strategy: validation

Validate before calling

String sanitizeX(String p){ return p.replaceAll("X{4,}", "XXX"); } // collapse long X runs
// or reject:
void assertShortX(String p){ if(p.matches(".*X{4,5}.*")) throw new IllegalArgumentException("FastDateParser supports at most XXX"); }

Try / catch

try { FastDateFormat.getInstance(pattern); }
catch (IllegalArgumentException e){ if(e.getMessage().contains("invalid number of X")) { pattern = pattern.replaceAll("X{4,}","XXX"); } else throw e; }

Prevention

When it happens

Trigger: A pattern containing four or five consecutive X characters (XXXX / XXXXX), e.g. 'yyyy-MM-dd'T'HH:mm:ssXXXXX'. Lengths outside {1,2,3} are rejected at parser construction time.

Common situations: Patterns copied from ISO-8601 examples or RFC 3339 that use the full 5-X form (e.g. for '+hh:mm' with optional colon and 'Z'); migrating code from SimpleDateFormat to Hutool's FastDateFormat.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/6b4ed7a2a0813b11. Report an issue: GitHub.