Repository navigation
docs: add a Building Apps guide on application-wide error handling - #6321
Merged
Merged
Conversation
Add articles/building-apps/ui-basics/handle-errors.adoc, a how-to guide for Flow applications covering the session ErrorHandler, custom not-found, access-denied, and unexpected-error views, the Spring Security catch-all rule, and where to handle exceptions thrown by application services (method security and optimistic locking). Replace the TODO in security/protect-views.adoc that waited for this page with a paragraph linking to it. Part of #6292 and #6288. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…curity tests Use the wording that #6320 gives the paragraph replacing the protect-views TODO, pointing its link at the new Handle Errors guide, so the overlap between the two PRs reduces to a one-line conflict. Link the guide to the Testing Method Security section that #6320 adds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Preview DeploymentThis PR has been deployed for preview. URL: https://docs-preview-pr-6321.fly.dev Changed pagesAdded content is highlighted in green; removed content is marked in red on each page.
Built from 373eebe |
- Move the catch-all ErrorView into the copy-paste example, out of the main layout (since vaadin/flow#22146, a failing layout makes Flow fall back to InternalServerError, which shows the exception message in production), and allow anonymous access to it. - Share logging, error IDs, and the user message between the error handler and the error view through a new ErrorReporter, which also adds exception details in development mode. - Make the error handler catch exceptions thrown while showing the message. - Add a section on customizing the internal error and session expired system messages. - Note that the HTTP status of an error view doesn't reach the browser on the initial page load (vaadin/flow#13421). - Mention that @ControllerAdvice doesn't apply to Flow views, that signal effects also reach the error handler, and two alternatives for larger applications: user-facing exception types and per-exception handlers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uide # Conflicts: # articles/building-apps/security/protect-views.adoc
peholmst
added a commit
that referenced
this pull request
Oct 9, 2026
Fixes six inaccuracies in reference pages about error handling, found while writing the error-handling guide in #6321. Each was checked against the Flow 25.3.3 sources (`com.vaadin:flow-server`), and the Observability Kit item was also checked against the kit's own bytecode. | Page | Was | Now | |---|---|---| | `tools/observability/reference.adoc` | Listed a throwing `beforeEnter()` among the failures routed to the session error handler | `Router.navigate()` catches every navigation exception and renders an error view through `handleExceptionNavigation()`, so these never reach the `ErrorHandler` and `vaadin.errors` doesn't count them. A short paragraph now says so and points to the navigation timer. In the kit, only `ErrorMetricsBinder` (the decorated handler) and `RequestMetricsBinder` (the request interceptor) increment `vaadin.errors`. | | `flow/configuration/properties.adoc` | Documented `enableErrorHandlerRedirect` (default `false`) | Removed. `InitParameters` has no such parameter. It was added in vaadin/flow#17791 and removed in vaadin/flow#18105 before 24.3.0 shipped. `DefaultErrorHandler.error()` always calls `ErrorHandlerUtil.handleErrorByRedirectingToErrorView()`. The sentence in `custom-error-handler.adoc` that said this behavior had to be "enabled" is reworded to match. | | `flow/routing/exceptions.adoc` | "Only extending instances are allowed." | Any `HasErrorParameter` for the same exception type replaces a `@DefaultErrorHandler` view, whether it extends it or not (`AbstractRouteRegistry.handleRegisteredExceptionType`). Two of your own handlers for the same type must be in a subclass relationship (the subclass wins), or startup fails with `InvalidRouteConfigurationException`. The same paragraph also named two classes that don't exist, `ParentLayouts` and `BeforeNavigationEvent`. They're now `@ParentLayout` and `BeforeEnterEvent`. | | `flow/advanced/custom-error-handler.adoc` | Wrapped `Notification.show()` in `UI.getCurrent().access()`, and the message had no space between "occurred." and "Contact" | Wrapper removed, because Flow calls the handler with the session locked. Space added. | | `flow/security/enabling-security.adoc` | Custom access-denied views returned `UNAUTHORIZED` (401) | `FORBIDDEN` (403), which fits an authenticated user who lacks permission. | | `building-apps/ui-basics/show-notification.adoc` | `VaadinIcon.CLOSE_SMALL` and `ButtonVariant.LUMO_TERTIARY_INLINE` | `VaadinIcon.CLOSE` (`CLOSE_SMALL` is `@Deprecated(since = "25.3", forRemoval = true)`) and the theme-neutral `ButtonVariant.TERTIARY`. | Vale reports no alerts on the changed lines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
peholmst
added a commit
that referenced
this pull request
Oct 9, 2026
…y, use Master-Detail Layout for form drawers (#6330) Closes #6292. This is the second batch. The first one was #6320, and #6321 added the error-handling guide. ## Section landing pages Seven Building Apps section landing pages had front matter but no content: UI Basics, Views & Navigation, Forms & Data, Business Logic, Security, Integration, and Components. Each now has a short introduction, where to start, links to related sections, and a `== Topics` outline. This follows the pattern of the Testing and React Views pages. Front matter fixes on these pages: - **Forms & Data** and **Add a Form**: removed the promise of forms "using both Flow and Hilla". This covers that bullet in #6293. - **Integration**: the section has a single page, on exposing a REST API, so the page title, description, and meta-description now say that instead of "integrate with other systems". The intro says that calls to other systems belong in application services. - **Security**: the intro links the OAuth2 reference page, which Add Login doesn't link (#6288, finding 4). It also links both security-testing pages. - Meta-descriptions are now 150–160 characters. The Components meta-description is still 126, as before; I didn't change it. ## Strong Consistency Replaced the stub and its TODO ("monoliths and self-contained systems") with four sections: - **Transactions**, and how application services define them - **Where Strong Consistency Ends**: a monolith or self-contained system can use one local transaction, while microservices can't, which leads to Eventual Consistency - **Concurrent Updates**: lost updates, optimistic locking, and pessimistic locking - **Stale Data in the User Interface**: strong consistency doesn't refresh views that are already open; server push does ## Dialogs & Drawers The drawer section had a TODO saying "Write about the new master-detail layout" and built the drawer by hand. It used `setVisible()` and `LumoUtility` classes. It now uses `MasterDetailLayout`: - The view extends `MasterDetailLayout`. It calls `setDetail(drawer)` when a proposal is selected and `setDetail(null)` when the selection is cleared. - The backdrop-click and Escape listeners clear the selection when the drawer is shown as an overlay. - It links to the Add a Master-Detail View guide. - It removes the `LumoUtility` styling (part of #6293). - It fixes `setAriaLabeledBy`, which doesn't exist, to `setAriaLabelledBy`. The example uses only `MasterDetailLayout` API that is available from 25.0. `setDetailPlaceholder()` (25.2) is avoided, so no since badge is needed. ## Checks - Compiled `ProposalDrawer` and `ProposalView`, extracted from the page, with `javac -Xlint:deprecation` against this repo's dependency classpath. The only stubs were `Proposal`, `ProposalForm`, and `ProposalService`. There were no errors or warnings. - All 52 added xrefs and anchors resolve. - Vale reports nothing on the changed lines. - No pages moved or removed, so no redirects are needed. After this PR, the only `// TODO` left in Building Apps and Getting Started is the one in `add-login.adoc`. It's a placeholder inside the code sample for the reader to fill in, so it stays. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a how-to guide on application-wide error handling for Flow applications, and replaces the TODO in Protect Views that was waiting for it.
Part of #6292 (the
security/protect-views.adoc#L291TODO) and #6288 ("Application-wide error handling and recovery").What's in the guide
New page:
articles/building-apps/ui-basics/handle-errors.adoc(Handle Errors)Copy-paste example:
ErrorReporterlogs each error with a short error ID and builds the user message, which includes the exception in development mode only.ApplicationErrorHandlershows that message in a closable notification.ErrorViewreplacesInternalServerErrorwith a standalone,@AnonymousAllowedpage.ErrorHandlingConfiginstalls the handler for every session.What users see by default, in development vs. production mode, for listener exceptions, not-found routes, access-denied navigation, and exceptions thrown during navigation.
Unexpected errors: guidance on what not to show users, error IDs, the null-UI case, an error handler that must never throw, unwrapping the cause chain, the exact-type error-view redirect that the default handler does,
@ControllerAdvicenot applying to Flow views, background threads, the internal error and session expired system messages, and monitoring.Navigation errors:
@AccessDeniedErrorRouterfor views that should stay hidden;VaadinSecurityConfigurercatch-all rule for typed or bookmarked URLs;It also notes that the HTTP status an error view returns doesn't reach the browser on the initial page load (Status returned by HasErrorParameter#setErrorParameter is ignored. flow#13421).
Exceptions from services:
AccessDeniedExceptiongoes to the error handler, with a pointer to splitting the handler into per-exception handlers as it grows;OptimisticLockingFailureExceptionis caught in the view that saves.Changes from external research
A second commit applies findings from the Vaadin forum, Martin Vysny's error-handling article, the Jmix and Error Window add-on approaches, Flow GitHub issues, and internal Slack threads in #flow-user.
ErrorViewout of the main layout. Since MainLayout unresponsive after unhandled exception in afterNavigation() flow#22146, if the layout itself throws, Flow falls back toInternalServerError, which shows the exception message in production.ErrorReporterfor both the handler and the error view. In #flow-user, developers asked for one example that covers both error paths.@ControllerAdvice, signal effects, and the two alternatives for larger applications.Placement
Under UI Basics, after Show a Notification and the other UI how-tos (order 40):
Overlap with #6320
#6320 also replaces the TODO in
security/protect-views.adoc. This PR uses the same paragraph wording but changes its link from Custom Error Handling to the new guide. It also adds one sentence that points to the guide's section on access-denied navigation. Git can't merge the two edits to that line automatically, so whichever PR merges second gets a one-line conflict. To resolve it, keep this PR's version of the paragraph.The guide also links to
protect-services#testing-method-security, a section that #6320 adds. If this PR merges first, the link opens Protect Services but doesn't jump to the section until #6320 is merged.Verification
get_java_symbol, 25.3). I also read the Flow 25.3.3 sources forDefaultErrorHandler,ErrorHandlerUtil,Router,InternalServerError,AbstractRouteNotFoundError,RouteAccessDeniedError,NavigationAccessControl,AnnotatedViewAccessChecker,UI.access(), and the error-target registry, and the Spring Security 7.1 sources for method-security denial.javac, including the revised copy-paste classes and the system messages bean, together with minimal stubs (MainLayout,HomeView,ProposalService, …), against this repo's dependency classpath (Vaadin 25.4.0-alpha1, Spring Boot 4.1). They compile with no deprecation warnings.VaadinIcon.CLOSE_SMALLis deprecated, so the code usesVaadinIcon.CLOSE.🤖 Generated with Claude Code