Skip to content

UI: Show clear permission toast for 403 errors on user actions#61588

Open
Abhishekmishra2808 wants to merge 12 commits intoapache:mainfrom
Abhishekmishra2808:fix-403-permission-error
Open

UI: Show clear permission toast for 403 errors on user actions#61588
Abhishekmishra2808 wants to merge 12 commits intoapache:mainfrom
Abhishekmishra2808:fix-403-permission-error

Conversation

@Abhishekmishra2808
Copy link
Contributor

@Abhishekmishra2808 Abhishekmishra2808 commented Feb 7, 2026

Description

Fixes #61460

This PR improves the user experience when an action fails due to insufficient permissions.

A global React Query MutationCache error handler now intercepts HTTP 403 (Forbidden) responses and displays a clear toast message:

Insufficient Permissions — You do not have permission to perform this action.

The toast is deduplicated to prevent spam when multiple mutations fail simultaneously. Existing retry behavior and error propagation remain unchanged.
Scope is intentionally limited to mutations (user actions) to avoid noisy background query refresh toasts.
This provides clearer feedback for protected UI actions (such as triggering DAGs or editing resources) with minimal risk and no behavioral side effects.

AFTER

image

@jscheffl
Copy link
Contributor

jscheffl commented Feb 7, 2026

Static checks are failing, please take a look to setup local validations: https://github.com/apache/airflow/blob/main/contributing-docs/03a_contributors_quick_start_beginners.rst

@choo121600
Copy link
Member

It would be helpful for the review if you could add a screenshot showing how the toast message looks😀

@bbovenzi
Copy link
Contributor

Instead of manually writing error messages in the UI, it would be better to make sure that fastapi is sending the correct error messages or that the UI is using the correct error message that is coming from the API.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, thanks for the PR.

Also we probably need to do some cleaning because in multiple places we still have the specific mutation onError hook that will also raise a toaster. We end up displaying two toasters.

Screen.Recording.2026-02-12.at.16.43.01.mov

…dling

- Add isActive() method to toaster abstraction for consistency
- Implement centralized 403 error handling in MutationCache
- Use i18n translations instead of hard-coded strings
- Update all mutation hooks to skip 403 errors (handled centrally)
- Prevent duplicate toaster notifications for permission errors
@Abhishekmishra2808
Copy link
Contributor Author

Hi @pierrejeambrun,
I’ve addressed all the suggestions you shared. I’ve also attached a screenshot showing the updated behavior, the duplicate toaster issue is now resolved.

Please let me know if anything else needs improvement.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good and working as expected.

Just a couple suggestions and we should be able to move merge.

- Extract error handling logic into shared utility function
- Create createErrorToaster in airflow-core/src/airflow/ui/src/utils/errorHandling.ts
- Function safely extracts HTTP status from error.status or error.response?.status
- Skips 403 errors (handled by MutationCache)
- Type-safe implementation with no 'any' types
- Update useClearRun.ts to use new utility function
- Export createErrorToaster from utils/index.ts

This utility can be reused across 15+ files with similar error handling patterns.
- Fix object stringification error by providing default message
- Refactor createErrorToaster to meet max-params rule (3 params max)
- Sort object type properties alphabetically per perfectionist rule
@Abhishekmishra2808
Copy link
Contributor Author

@pierrejeambrun fixed all the changes suggested by you, could you please review it now?

@Abhishekmishra2808
Copy link
Contributor Author

@pierrejeambrun Please re-run the CI and review this please. sorry for pinging you again

@Abhishekmishra2808
Copy link
Contributor Author

Abhishekmishra2808 commented Mar 6, 2026

@choo121600 @pierrejeambrun please check it now !

@choo121600
Copy link
Member

The i18n keys errors.forbidden.description and errors.forbidden.title seem to be missing from the translation files.
Could you please add them?

@Abhishekmishra2808
Copy link
Contributor Author

@choo121600 added them in the latest commit, please check it now !

Comment on lines +38 to +40
const status =
(error as unknown as { status?: number }).status ??
(error as unknown as { response?: { status?: number } }).response?.status;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should pull this out into a util instead of copy-pasting this code all over.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bbovenzi Nice Idea, Please check out the latest commit!

@eladkal eladkal added this to the Airflow 3.1.9 milestone Mar 6, 2026
@eladkal eladkal added type:bug-fix Changelog: Bug Fixes backport-to-v3-1-test Mark PR with this label to backport to v3-1-test branch labels Mar 6, 2026
@Abhishekmishra2808
Copy link
Contributor Author

addressed all the concern told by the reviewers. This PR is ready for the final review.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You introduced a new getErrorStatus and getErrorMessage that is only used in this PR while the entire codebase is still doing manual check everywhere else. It wouldn't be needed if you were using the createErrorToaster everywhere as requested above. No idea why the createErrorToaster is only used 3 times, and most of the time we still do that creation manually.

This is taking a lot of back and forth and energy for something that isn't suppose to. Please make sure you address properly and spend the time to make the code as maintainable and readable as possible before asking for a final review.

Comment on lines +51 to +53
const status =
(error as { status?: number }).status ?? (error as { response?: { status?: number } }).response?.status;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use getStatus? Same for other places.

@pierrejeambrun
Copy link
Member

Common function was merged, can you re-use it in this PR? createErrorToaster from #61560

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:UI Related to UI/UX. For Frontend Developers. backport-to-v3-1-test Mark PR with this label to backport to v3-1-test branch type:bug-fix Changelog: Bug Fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When a DAG Viewer tries to trigger a DAG, the action fails with 403

6 participants