Conversation
favorite_dag returns 409 when the Dag is already a favorite, and its test has asserted that since apache#51264, but the response was never declared, so it is missing from the OpenAPI spec and every client generated from it. The 409 also came from the generic unique-constraint handler, so a repeat favorite answered "Serious error when handling your request" and logged an error, while unfavorite_dag answers "Dag is not marked as favorite". Check for the row first, as unfavorite_dag does, and declare the 409.
vsima
requested review from
bbovenzi,
bugraoz93,
choo121600,
ephraimbuddy,
guan404ming,
henry3260,
jason810496,
pierrejeambrun,
rawwar,
ryanahamilton,
shubhamraj-git and
vatsrahul1001
as code owners
September 20, 2026 15:46
|
Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
|
vsima
marked this pull request as draft
September 20, 2026 15:49
It pinned behaviour this change does not touch, which the review guidelines count as padding rather than coverage.
vsima
marked this pull request as ready for review
September 20, 2026 17:10
bbovenzi
approved these changes
Sep 21, 2026
Author
|
Thanks for the review. The two failures are infra: an artifact-upload 403 in Latest Boto (its tests passed) and a connection reset in the FAB docs spellcheck. Would someone mind re-running those two jobs? |
Contributor
|
As a non-committer, we can trigger CI ourselves -- simply turn it into draft PR and reopen it again. |
This branch has not been deployed
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.
Document the 409 on
POST /dags/{dag_id}/favorite, and make its body match its sibling.Two related problems on the same endpoint pair.
The published spec contradicts the project's own test.
favorite_dagdeclares
create_openapi_http_exception_doc([404])whileunfavorite_dagdeclares
[404, 409]. Favoriting an already-favorited Dag does return 409 —test_favoriting_already_favorited_dag_returns_409has asserted exactly thatsince the endpoint was added in #51264. Because the response was never declared, it is
absent from
v2-rest-api-generated.yaml, and so from every client generatedfrom it: a generated client sees an undeclared status and surfaces it as an
unexpected error rather than "already a favorite".
The two endpoints answer the same conflict differently.
unfavorite_dagchecks for the row and raises a 409 with
Dag is not marked as favorite.favorite_daghas no check, so the duplicate insert violates the uniqueconstraint and is caught by the generic
_UniqueConstraintErrorHandler. Thebody a user gets for favoriting twice is:
{ "message": "Serious error when handling your request. Check logs for more details - you will find it in api server when you look for ID 6Q4Msafe", "orig_error": "hidden", "reason": "Unique constraint violation", "statement": "hidden" }Favoriting something that is already a favorite is a stale toggle (a second
tab, a cached list, an API client retrying), not a serious error, and it does not warrant sending an operator into the API
server logs after a correlation ID. The same user error produces a clean,
translatable message in one direction and this in the other.
This adds the existence check to
favorite_dag, mirroringunfavorite_dagtwenty lines below, and declares the 409.
Behaviour change, stated plainly: the status code does not change. The
409's
detailchanges from the handler's object above (which also carries theSQL statement and dialect error when
[api] expose_stacktraceis on) to thestring
Dag is already marked as favorite, the same shapeunfavorite_dagreturns. A repeat favorite also stops writing an ERROR-level line to the API
server log. Anything matching on the old payload would be affected; the only
in-tree references to
Unique constraint violationare the handler's own testsin
test_exceptions.py, which do not touch this endpoint, and the UI does notbranch on either message.
On the race: the check is not atomic, so two concurrent favorite calls can
still reach the unique constraint and return the handler's 409. That is the
same window
unfavorite_daghas, and the status is unchanged either way, sothis keeps the existing pattern rather than introducing a different one here.
Happy to take the
ON CONFLICT DO NOTHINGroute instead if reviewers prefer.Tests:
test_favoriting_already_favorited_dag_returns_409now asserts thebody as well as the status. The new probe gets
test_favorite_dag_existence_check_is_bounded, the twin of the existingunfavorite test, so both existence checks are held to
LIMIT 1.Verified locally:
pytest tests/unit/api_fastapi/core_api/routes/public/test_dags.py -k favoritegives 17 passed. Reverting the route change alone makes
test_favoriting_already_favorited_dag_returns_409fail on the body, which iswhere the payload above came from, so the assertion is pinned to the fix rather
than passing incidentally.
The spec and the UI client (
types.gen.ts,services.gen.ts) are the outputof
run_generate_openapi_spec.pyandpnpm codegen; nothing else in thegenerated files moved.
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5, Fable 5.1) following the guidelines