spring-projects/spring-security · error · UnsupportedOperationException

encode is not supported

Error message

encode is not supported

What it means

UnmappedIdPasswordEncoder is the default matcher used when an encoded password's id has no registered delegate. Matching may be delegated to it, but encoding is meaningless (it would have to pick an arbitrary id), so encodeNonNullPassword unconditionally throws UnsupportedOperationException.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java:291

			String encodedPassword = extractEncodedPassword(prefixEncodedPassword);
			return this.passwordEncoderForEncode.upgradeEncoding(encodedPassword);
		}
	}

	private String extractEncodedPassword(String prefixEncodedPassword) {
		int start = prefixEncodedPassword.indexOf(this.idSuffix);
		return prefixEncodedPassword.substring(start + this.idSuffix.length());
	}

	/**
	 * Default {@link PasswordEncoder} that throws an exception telling that a suitable
	 * {@link PasswordEncoder} for the id could not be found.
	 */
	private class UnmappedIdPasswordEncoder extends AbstractValidatingPasswordEncoder {

		@Override
		protected String encodeNonNullPassword(String rawPassword) {
			throw new UnsupportedOperationException("encode is not supported");
		}

		@Override
		protected boolean matchesNonNull(String rawPassword, String prefixEncodedPassword) {
			String id = extractId(prefixEncodedPassword);
			if (id != null && !id.isBlank()) {
				throw new IllegalArgumentException(String.format(NO_PASSWORD_ENCODER_MAPPED, id));
			}
			if (prefixEncodedPassword != null && !prefixEncodedPassword.isBlank()) {
				int start = prefixEncodedPassword.indexOf(DelegatingPasswordEncoder.this.idPrefix);
				int end = prefixEncodedPassword.indexOf(DelegatingPasswordEncoder.this.idSuffix, start);
				if (start < 0 && end < 0) {
					throw new IllegalArgumentException(NO_PASSWORD_ENCODER_PREFIX);
				}
			}
			throw new IllegalArgumentException(String.format(MALFORMED_PASSWORD_ENCODER_PREFIX,
					DelegatingPasswordEncoder.this.idPrefix, DelegatingPasswordEncoder.this.idSuffix));
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Encode via a real delegate encoder (e.g. BCryptPasswordEncoder) or ensure the DelegatingPasswordEncoder was built with a valid idForEncode registered in idToPasswordEncoder
  2. Catch UnsupportedOperationException and route encoding to an actual encoder
  3. Do not expose the UnmappedIdPasswordEncoder inner encoder as the encoding path in custom code

Example fix

// before
String encoded = unmappedIdEncoder.encode(rawPassword); // throws
// after
String encoded = delegatingPasswordEncoder.encode(rawPassword); // uses idForEncode delegate
Defensive patterns

Strategy: try-catch

Validate before calling

if (encoder instanceof DelegatingPasswordEncoder d) {
    // ensure encoding goes through a real delegate, i.e. the encoder was built with a valid idForEncode
}

Type guard

if (encoder instanceof DelegatingPasswordEncoder) {
    // safe to encode(); the UnmappedId placeholder is internal and not normally exposed
}

Try / catch

try {
    encoded = encoder.encode(rawPassword);
} catch (UnsupportedOperationException e) {
    encoded = realDelegateEncoder.encode(rawPassword);
}

Prevention

When it happens

Trigger: Calling encode() on a DelegatingPasswordEncoder whose configured idForEncode resolves to the internal UnmappedIdPasswordEncoder — practically, calling encode on a misconstructed or misused delegating encoder rather than a real delegate.

Common situations: Reflection or framework code resolving the encoder by type and invoking encode without knowing it is the unmapped-id placeholder; custom subclassing that routes encoding through the fallback encoder.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/04507421e1302840. Report an issue: GitHub.