spring-projects/spring-security · error · DataRetrievalFailureException
The ClientRegistration with id '${clientRegistrationId}' exi
Error message
The ClientRegistration with id '${clientRegistrationId}' exists in the data source, however, it was not found in the ClientRegistrationRepository. What it means
JdbcOAuth2AuthorizedClientService.OAuth2AuthorizedClientRowMapper loads an OAuth2AuthorizedClient row from the database and resolves the ClientRegistration via the configured ClientRegistrationRepository. When the repository cannot find a registration matching the row's client_registration_id, it throws this DataRetrievalFailureException, because an authorized client row without a corresponding in-memory registration cannot be reconstructed.
Source
Thrown at oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/JdbcOAuth2AuthorizedClientService.java:262
protected LobHandler lobHandler = new DefaultLobHandler();
public OAuth2AuthorizedClientRowMapper(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.clientRegistrationRepository = clientRegistrationRepository;
}
public final void setLobHandler(LobHandler lobHandler) {
Assert.notNull(lobHandler, "lobHandler cannot be null");
this.lobHandler = lobHandler;
}
@Override
public OAuth2AuthorizedClient mapRow(ResultSet rs, int rowNum) throws SQLException {
String clientRegistrationId = rs.getString("client_registration_id");
ClientRegistration clientRegistration = this.clientRegistrationRepository
.findByRegistrationId(clientRegistrationId);
if (clientRegistration == null) {
throw new DataRetrievalFailureException(
"The ClientRegistration with id '" + clientRegistrationId + "' exists in the data source, "
+ "however, it was not found in the ClientRegistrationRepository.");
}
OAuth2AccessToken.TokenType tokenType = null;
if (OAuth2AccessToken.TokenType.BEARER.getValue().equalsIgnoreCase(rs.getString("access_token_type"))) {
tokenType = OAuth2AccessToken.TokenType.BEARER;
}
OAuth2AccessToken.TokenType tokenTypeToUse = (tokenType != null) ? tokenType
: OAuth2AccessToken.TokenType.BEARER;
String tokenValue = new String(this.lobHandler.getBlobAsBytes(rs, "access_token_value"),
StandardCharsets.UTF_8);
Timestamp issuedAtTs = rs.getTimestamp("access_token_issued_at");
Timestamp expiresAtTs = rs.getTimestamp("access_token_expires_at");
Instant issuedAt = (issuedAtTs != null) ? issuedAtTs.toInstant() : null;
Instant expiresAt = (expiresAtTs != null) ? expiresAtTs.toInstant() : null;
Set<String> scopes = Collections.emptySet();
String accessTokenScopes = rs.getString("access_token_scopes");
if (accessTokenScopes != null) {View on GitHub (pinned to 96852e8860)
Solutions
- Delete or clean stale rows in oauth2_authorized_client whose client_registration_id no longer exists in the repository.
- Restore the missing registration in your ClientRegistrationRepository / application properties so the id matches the DB rows.
- If registrations are dynamic, use a ClientRegistrationRepository that can resolve all persisted registration ids (e.g. a Jdbc-backed or issuer-based repository).
- Use a custom RowMapper or wrap the service to skip/log rows whose registration is absent instead of failing the whole load.
Example fix
// before: stale DB rows for removed client 'old-client' spring.security.oauth2.client.registration.old-client.client-id=... // after: either re-add the registration or purge rows DELETE FROM oauth2_authorized_client WHERE client_registration_id = 'old-client';
Defensive patterns
Strategy: try-catch
Validate before calling
boolean registered = clientRegistrationRepository.findByRegistrationId(rowId) != null;
if (!registered) { /* skip/purge row or re-add registration */ } Type guard
boolean hasRegistration(String id) {
return clientRegistrationRepository.findByRegistrationId(id) != null;
} Try / catch
try {
OAuth2AuthorizedClient client = service.loadAuthorizedClient(registrationId, principalName);
} catch (DataRetrievalFailureException ex) {
// purge stale row or fall back to a fresh authorization flow
log.warn("orphaned authorized client row: {}", ex.getMessage());
} Prevention
- Treat ClientRegistrationRepository and the DB as one unit: migrate/clean oauth2_authorized_client rows whenever registrations are renamed or removed.
- Use a shared/JDBC-backed registration repository when clients are managed dynamically.
- Monitor for the error to detect config drift between properties and database.
When it happens
Trigger: Calling loadAuthorizedClient/removeAuthorizedClient/updateAuthorizedClient on JdbcOAuth2AuthorizedClientService when the oauth2_authorized_client table contains a row whose client_registration_id is not registered in the ClientRegistrationRepository (which is typically an InMemoryClientRegistrationRepository built from static spring.security.oauth2.client.registration.* properties).
Common situations: Client registration removed or renamed in application.yml while old authorized-client rows persist in the database; multi-tenant setups where rows are written for registrations that are not loaded on that instance; switching from a dynamic/OIDC-discovery repository to a static one; running multiple apps or profiles against a shared database.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Unable to create an {OAuth2AuthorizedClientManager} bean. Ex
- invalid_dpop_proof
- invalid_scope
- oidc_provider_not_configured
- No enum constant org.springframework.security.oauth2.client.
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/889aa38b2857a950.
Report an issue: GitHub.