diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/LoggingRequestCycleListener.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/LoggingRequestCycleListener.java
index b6e63e6eb9b..266992aeab0 100644
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/LoggingRequestCycleListener.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/LoggingRequestCycleListener.java
@@ -9,6 +9,8 @@
import org.apache.wicket.Application;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
+import org.apache.wicket.core.request.mapper.StalePageException;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.component.IRequestablePage;
@@ -49,6 +51,14 @@ public IRequestHandler onException(RequestCycle cycle, Exception ex) {
REQUEST_LOGGER.trace("REQUEST CYCLE: Exception: {}, handler {}", ex,
WebComponentUtil.debugHandler(cycle.getActiveRequestHandler()), ex);
}
+ if (ex instanceof StalePageException stalePageException) {
+ // Wicket uses this exception for stale render-count recovery, e.g. after browser view-source.
+ // Do not convert it to PageError/500, recover by re-rendering the stale page.
+ LOGGER.debug("Recovering stale Wicket page request by re-rendering page {}", stalePageException.getPage());
+ return new RenderPageRequestHandler(
+ new PageProvider(stalePageException.getPage()),
+ RedirectPolicy.ALWAYS_REDIRECT);
+ }
LoggingUtils.logUnexpectedException(LOGGER, "Error occurred during page rendering", ex);
return new RenderPageRequestHandler(new PageProvider(new PageError(ex)));
}
@@ -136,4 +146,3 @@ public void onUrlMapped(RequestCycle cycle, IRequestHandler handler, Url url) {
}
}
}
-
diff --git a/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/LoggingRequestCycleListenerTest.java b/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/LoggingRequestCycleListenerTest.java
new file mode 100644
index 00000000000..9df959f9e3f
--- /dev/null
+++ b/gui/admin-gui/src/test/java/com/evolveum/midpoint/web/LoggingRequestCycleListenerTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010-2026 Evolveum and contributors
+ *
+ * This work is dual-licensed under the Apache License 2.0
+ * and European Union Public License. See LICENSE file for details.
+ */
+
+package com.evolveum.midpoint.web;
+
+import com.evolveum.midpoint.web.security.LoggingRequestCycleListener;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
+import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
+import org.apache.wicket.core.request.mapper.StalePageException;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.util.tester.WicketTester;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests exception handling behavior in {@link LoggingRequestCycleListener}.
+ */
+public class LoggingRequestCycleListenerTest {
+
+ /**
+ * MID-9998: Verifies that Wicket stale page recovery, e.g. after browser
+ * view-source, is handled by re-rendering the stale page instead of being
+ * converted to the error page / HTTP 500.
+ */
+ @Test
+ public void testStalePageExceptionIsRecoveredInsteadOfConvertedToPageError() {
+ WicketTester tester = new WicketTester();
+ try {
+ LoggingRequestCycleListener listener = new LoggingRequestCycleListener(tester.getApplication());
+ TestPage page = new TestPage();
+
+ IRequestHandler handler = listener.onException(null, new StalePageException(page));
+
+ Assert.assertTrue(handler instanceof RenderPageRequestHandler);
+
+ RenderPageRequestHandler renderHandler = (RenderPageRequestHandler) handler;
+ Assert.assertSame(renderHandler.getPage(), page);
+ Assert.assertSame(renderHandler.getRedirectPolicy(), RedirectPolicy.ALWAYS_REDIRECT);
+ } finally {
+ tester.destroy();
+ }
+ }
+
+ private static class TestPage extends WebPage {
+ }
+}
diff --git a/gui/admin-gui/testng-unit.xml b/gui/admin-gui/testng-unit.xml
index 4759da96677..3caef0c5ea7 100644
--- a/gui/admin-gui/testng-unit.xml
+++ b/gui/admin-gui/testng-unit.xml
@@ -14,6 +14,7 @@
+
diff --git a/release-notes.adoc b/release-notes.adoc
index 6c212cea90d..0be0f8a2c1b 100644
--- a/release-notes.adoc
+++ b/release-notes.adoc
@@ -140,6 +140,7 @@ Overall, midPoint 4.10 opens up the world of identity management and governance
* Fixed missing .zip extension when downloading tracing report files. See bug:MID-11096[]
* Fixed resource wizard mapping property autocomplete to find partial matches regardless of letter case. See bug:MID-10415[]
* Fixed missing input variable in resource activation existence mappings. See bug:MID-10905[]
+* Fixed stale page recovery after viewing page source causing internal server error. See bug:MID-9998[]
=== Releases Of Other Components