Troubleshooting
Common problems and how to fix them. If you do not find your issue here, open a GitHub issue.
Provider not loading in Keycloak
Symptom: The "Email OTP" authenticator does not appear in the Add step list.
Causes and fixes:
- JAR not copied — confirm the file is in the providers directory:
docker exec keycloak ls -la /opt/keycloak/providers/
# Expected: keycloak-2fa-email-authenticator-26.4.0.jar
kc.sh buildnot run — Keycloak must re-index providers after the JAR is added. If you deployed the JAR manually (not via the Docker image), run:
<KEYCLOAK_HOME>/bin/kc.sh build
-
Wrong JAR version — the JAR version must be compatible with your Keycloak version. Check Maven Central for the correct version matching your
KC<version>suffix. -
Keycloak not restarted — restart the container after adding the JAR:
docker restart keycloak
OTP form never appears after login
Symptom: Users log in with username + password and land directly in the app — no OTP prompt.
Causes and fixes:
-
Flow not bound — the new flow must be bound to Browser Flow under Authentication → Flows → Action → Bind flow. Creating the flow is not enough.
-
Wrong realm — confirm the flow is bound in the same realm where users are logging in.
-
Conditional 2FA sub-flow misconfigured — the "Browser with Email OTP Forms - Conditional 2FA" sub-flow requires at least one condition execution (e.g. "Condition - User Configured"). Without one, it always evaluates to false and the OTP step is skipped. Either switch to REQUIRED or add a condition. See Add the OTP Execution.
-
ALTERNATIVE requirement satisfied by another factor — if another step already satisfies the flow, the OTP step is skipped. Switch the Email OTP requirement to REQUIRED.
Email OTP does not appear under "Try Another Way"
The Email OTP execution is credential-based. Like Keycloak's built-in OTP and WebAuthn, Keycloak only offers it as an alternative to users who have enrolled the email authenticator.
- To offer it to users who never enrolled, use the Email OTP (No Enrollment) execution instead. See Add the OTP Execution.
- To keep enrollment, have users enroll from the account console, or assign them the
email-authenticator-setuprequired action.
Build errors
Tests failing on Java 25+
Mockito and ByteBuddy have compatibility issues with Java 25+. Build with tests skipped:
mvn clean package -DskipTests
Use Java 21 for active development to keep the full test suite passing.
JAVA_HOME not set correctly
- macOS
- Linux
- Windows
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
java -version
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
java -version
set JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-21.0.x.x-hotspot
java -version
Container / Docker issues
Port 8080 already in use
# Run on a different host port
docker run -d -p 8081:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
keycloak-2fa-email:latest start-dev
# Access at http://localhost:8081
Container exits immediately
Check the logs for the actual error:
docker logs keycloak
Common causes:
- Port conflict (see above)
- Missing environment variables (
KEYCLOAK_ADMIN/KEYCLOAK_ADMIN_PASSWORD) - Out of memory — try increasing Docker's memory limit to at least 2 GB
Image build fails
# Clean Docker cache and rebuild
docker builder prune
docker build --no-cache -t keycloak-2fa-email:latest .
Email delivery issues
See the Email Providers — Troubleshooting section for provider-specific error tables (SendGrid, AWS SES, Mailgun, SMTP).
Quick diagnostic checklist:
- Use Realm Settings → Email → "Test connection" to verify SMTP works independently
- Enable Simulation mode in the OTP settings to confirm the authenticator runs without actually sending email
- Check Keycloak server logs for errors:
docker logs keycloak 2>&1 | grep -iE "error|exception|email|provider"
- Confirm the user account has an email address set and Email Verified is ON
Localization / wrong language displayed
Symptom: OTP messages appear in the wrong language or fall back to English unexpectedly.
Causes and fixes:
-
Internationalization not enabled — go to Realm Settings → Localization → enable Internationalization and add the target locale.
-
Missing properties file — if you added a custom language, the file must be in
src/main/resources/theme-resources/messages/messages_<code>.propertiesand the project must be rebuilt. -
Browser locale not matching — Keycloak can use the browser's
Accept-Languageheader. Test by switching your browser language or using the locale selector on the login page. -
RTL layout issues (Arabic) — ensure your Keycloak theme supports RTL. The default Keycloak theme has partial RTL support; a custom theme may be needed for full RTL rendering.
Still stuck?
- Browse existing issues — someone may have hit the same problem
- Open a new issue with:
- Keycloak version
- Plugin version (
26.x.x-KCxx.x.x) - Relevant logs
- Steps to reproduce