Uh oh!
There was an error while loading. Please reload this page.
Fix upstream map index resolution after placeholder expansion - #59691
Conversation
79528c5 to
529673dCompareSameerMesiah97
commented
Dec 27, 2025
potiuk
commented
Dec 28, 2025
Also @uranusjr can help with review - there ias related WIP he eworks on now I think |
3b16811 to
cee1968CompareSameerMesiah97
commented
Jan 6, 2026
cee1968 to
630de66CompareSameerMesiah97
commented
Jan 18, 2026
I have checked the main branch using a variety of DAG shapes following the same theme as the one in the bug report and the issue is still present. So it appears any recent work in this specific area (that is separate from this PR) which has been merged into main, has not resolved the bug. As of this comment, I cannot see any open PRs that could resolve the issue (anyone reading this comment is free to correct me). This PR has been rebased and is ready for review. |
630de66 to
4bff1aeCompareSameerMesiah97
commented
Feb 21, 2026
I have checked main again using the same test cases and the issue is still present so the bug being addressed by this PR has not been resolved. I am unable to locate any open PRs that I would expect to fix this issue either. The bug silently renders certain DAG shapes unusable with Dynamic Task Mapping so I believe this should not be deprioritized. This PR has been open for approximately 2 months. It has now been rebased again and is ready for review. I have run the aforementioned test cases with my changes and I can confirm that they give the expected result. |
Nataneljpwd
commented
Mar 13, 2026
Hello @SameerMesiah97, I think there have been a lot of changes since you created the pr, the code you have won't work now as all parameters but the upstream, session and ti_count have been removed from the get_relevant_upstream_map_indexes method Could you check if the issue still persists? |
SameerMesiah97
commented
Mar 13, 2026
I checked 3 weeks ago but I will check again today. |
4bff1ae to
eac9478CompareSameerMesiah97
commented
Mar 13, 2026
Just checked again right now. The bug is still present in the main branch using the exact DAG shapes I used in my previous tests and my fix resolves it for all of these cases. I have rebased and force-pushed again. |
eac9478 to
6583275Compare654a660 to
a6e5910CompareSameerMesiah97
commented
May 22, 2026
Your feedback has been addressed. |
Quantum0uasar
commented
May 27, 2026
Reviewed the diff carefully. Great fix for a subtle race condition in dynamic task group expansion. A few observations: On
On the condition logic: return (
-1intask_to_map_indexes[task.task_id]
and-1notintask_to_map_indexes[relative.task_id]
and0intask_to_map_indexes[relative.task_id]
)Is the third condition ( On test coverage: Overall the approach is sound and the fix is minimal. Appreciate the thorough rebasing history on this one. |
Quantum0uasar
commented
May 27, 2026
Thanks for tackling this edge case — placeholder-to-expanded index transition bugs are notoriously hard to reproduce in dynamic task mapping. I reviewed the logic and have a few observations: On the core helperThe guard condition: return (
-1intask_to_map_indexes[task.task_id] and-1notintask_to_map_indexes[relative.task_id] and0intask_to_map_indexes[relative.task_id]
)This reads cleanly, but I’d flag one subtle case: what if the upstream expands to more than one instance (e.g., On DB query costThe reviewer note about unnecessary DB queries is important. If all_indexes=session.execute(
select(TI.task_id, TI.map_index)
.where(TI.dag_id==dag_id, TI.run_id==run_id)
).all()
task_to_map_indexes=defaultdict(set)
fortask_id, map_indexinall_indexes:
task_to_map_indexes[task_id].add(map_index)This avoids the query amplification problem especially for wide DAGs. Test coverage gapThe existing regression tests cover:
One gap: a test where the upstream has not yet been expanded (placeholder still active). The fix should be a no-op in that case, but it’s easy to accidentally break this when changing the condition. Also agree with the reviewer’s request for an Minor
Overall the fix is targeted and correct for the primary case. The main risk area is the fan-out upstream scenario and DB query cost at scale. Happy to look at the full diff in |
return bool instead of 0/None, and simplify the associated resolution logic and documentation.
a6e5910 to
e3b0637CompareSameerMesiah97
commented
May 27, 2026
Thanks for the review. I have added another phase in the existing test to cover the initial state where the upstream placeholder has not yet been expanded. A few clarifications on the other points:
|
SameerMesiah97
commented
Jun 1, 2026
I would appreciate another look. |
SameerMesiah97
commented
Jun 5, 2026
Requesting review for this. |
dabla
commented
Jun 10, 2026
@SameerMesiah97 have you tested this fix locally with Dynamic Task Expansion, any logs to prove that it the change fixes the issue? Maybe a stupid question, but that could help approve the PR as for me code is looking good, but of course I haven't tested it so I cannot confirm this will actually fix the issue. Nice work BTW. |
SameerMesiah97
commented
Jun 10, 2026
If by Dynamic Task Expansion you meant Dynamic Task Mapping, then yes. I have done several tests using a variety of DAG shapes at mutliple points in time whilst working on this PR. If you scroll up, you will see me reporting the results after each test run. I will do another test as soon as I am able to and I will provide all the details as well. |
SameerMesiah97
commented
Jun 10, 2026
I have ran the following DAG (closely mirrors the one used in issue #59289) using the code in This is the UI screenshot for the DAG run: The same DAG was run again using the branch which has my fix (rebased on top of the latest version of ![]() You can observe that the terminal tasks of both the DAG and the mapped group are no longer being skipped. I must admit that unlike in previous test runs, the DAG is being marked as successful. And amongst the other DAG shapes I tested, the bug is no longer present in |
Uh oh!
There was an error while loading. Please reload this page.
dabla
commented
Jun 11, 2026
Thanks for the nice work and patience @SameerMesiah97 ! |
…#59691) * Fix upstream map index resolution after placeholder expansion with unit test. * Rename placeholder map index helper to reflect boolean semantics, return bool instead of 0/None, and simplify the associated resolution logic and documentation. --------- Co-authored-by: Sameer Mesiah <smesiah971@gmail.com>
…#59691) * Fix upstream map index resolution after placeholder expansion with unit test. * Rename placeholder map index helper to reflect boolean semantics, return bool instead of 0/None, and simplify the associated resolution logic and documentation. --------- Co-authored-by: Sameer Mesiah <smesiah971@gmail.com>


Description
Fix upstream map index resolution for dynamically mapped task groups when placeholder task instances are replaced during expansion.
After expansion, the upstream placeholder (
map_index = -1) is replaced by the first expanded task instance (map_index = 0). Downstream task instances that are still unexpanded may continue to reference the placeholder, causing incorrect upstream dependency resolution.This change introduces a small helper (
_should_use_post_expansion_placeholder) that is invoked during upstream map index resolution to correctly handle this transition, while preserving existing behavior for already-expanded downstream tasks.Rationale
Placeholder task instances are a temporary pre-expansion representation. Once expansion occurs, they are no longer valid references, but downstream resolution logic may still encounter them. Handling this transition explicitly prevents downstream tasks from treating completed upstream work as unresolved.
This could cause implicit dependencies to be skipped during DAG evaluation under certain trigger rules (such as
NONE_FAILED_MIN_ONE_SUCCESS), particularly when multiple parallel task streams within theMappedTaskGroupconverge on a single downstream task outside the group. As a result, DAG runs could be incorrectly marked as failed or skipped despite valid upstream execution.Please refer to issue #59289 for more context. This PR was opened in response to that. The author of the issue reported the bug in Airflow 3.0.6 but I can confirm that the same issue is present in Airflow 3.1.5 (as well as the main branch at the time this PR was last updated).
Tests
Added a test covering the post-expansion state where:
The test asserts that
get_relevant_upstream_map_indexesreturns the correct upstream map index in both cases.Closes: #59289