chinabugotech/hutool · error · IllegalArgumentException

invalid number of X

Error message

invalid number of X

What it means

Same rule as the parser's 'X' guard, but for the printer side: Iso8601_Rule.getRule only returns a rule for token length 1, 2, or 3. Patterns with XXXX or XXXXX (four/five X's) hit the default branch and throw at printer construction time.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java:1226

		// Sign TwoDigitHours : Minutes or Z
		static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new Iso8601_Rule(6);

		/**
		 * Factory method for Iso8601_Rules.
		 *
		 * @param tokenLen a token indicating the length of the TimeZone String to be formatted.
		 * @return a Iso8601_Rule that can format TimeZone String of length {@code tokenLen}. If no such rule exists, an IllegalArgumentException will be thrown.
		 */
		static Iso8601_Rule getRule(int tokenLen) {
			switch (tokenLen) {
				case 1:
					return Iso8601_Rule.ISO8601_HOURS;
				case 2:
					return Iso8601_Rule.ISO8601_HOURS_MINUTES;
				case 3:
					return Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
				default:
					throw new IllegalArgumentException("invalid number of X");
			}
		}

		final int length;

		/**
		 * Constructs an instance of {@code Iso8601_Rule} with the specified properties.
		 *
		 * @param length The number of characters in output (unless Z is output)
		 */
		Iso8601_Rule(int length) {
			this.length = length;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Limit the X run to 1-3 (XXX yields '+hh:mm' or 'Z').
  2. Use java.text.SimpleDateFormat for the 4/5-X forms if required.
  3. Prefer the 'Z' token (TimeZoneNumberRule) for fixed offset formatting.

Example fix

// before
FastDateFormat fdf = FastDateFormat.getInstance("HH:mm:ssXXXXX");
// after
FastDateFormat fdf = FastDateFormat.getInstance("HH:mm:ssXXX");
Defensive patterns

Strategy: validation

Validate before calling

String collapseX(String p){ return p.replaceAll("X{4,}", "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: Building a FastDateFormat with a pattern containing four or five consecutive X's, e.g. 'HH:mmXXXXX'. The throw happens when the formatter is created, not when it formats a value.

Common situations: Porting ISO-8601 / RFC-3339 patterns that use the extended zone form; patterns generated from specs that enumerate all five X variants.

Related errors


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