Skip to content

Validate trigger events in Openai deferrable tasks - #69506

Merged
potiuk merged 2 commits into
apache:mainfrom
takayoshi-makabe:add-validate-trigger-events-openai-deferrable-tasks
Aug 1, 2026
Merged

Validate trigger events in Openai deferrable tasks#69506
potiuk merged 2 commits into
apache:mainfrom
takayoshi-makabe:add-validate-trigger-events-openai-deferrable-tasks

Conversation

@takayoshi-makabe

Copy link
Copy Markdown
Contributor

OpenAITriggerBatchOperator.execute_complete used the trigger event without validating it, branching deny-list style (only status == "error" raised, everything else succeeded):

  • cancelled was marked SUCCESS: the provider's own OpenAIBatchTrigger emits {"status": "cancelled"} when the batch is cancelled while the task is deferred, but only error raised — so the task went green with no results. The non-deferrable path (OpenAIHook.wait_for_batch) has raised for CANCELLED/CANCELLING since feat(providers/openai): support batch api in hook/operator/trigger #41554, so the two modes of the same operator disagreed.
  • event=None: crashed with an opaque TypeError: 'NoneType' object is not subscriptable.
  • Unrecognised status (triggerer/worker version skew, custom trigger): fell through into the success path.

Same fix shape as the anthropic provider in #69379: a validate_execute_complete_event() helper plus allow-list branching (status != "success" raises).

Also fixes a missing else in OpenAIBatchTrigger.run() that yielded a second, spurious error event after every terminal event (benign — only the first event is consumed — but incorrect).


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Claude Code


  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

@takayoshi-makabe takayoshi-makabe changed the title Add validate trigger events deferrable tasks Add validate trigger events deferrable tasks OpenAI provider Jul 7, 2026
@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jul 8, 2026
@takayoshi-makabe takayoshi-makabe changed the title Add validate trigger events deferrable tasks OpenAI provider Validate trigger events in Openai deferrable tasks Jul 11, 2026

@potiuk potiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Three real defects here, and the first is the one that matters most.

A batch cancelled while the task was deferred completed successfully with no results, because execute_complete only raised on status == "error". The non-deferrable path has raised for CANCELLED/CANCELLING since wait_for_batch was fixed, so the same operator disagreed with itself depending on whether deferrable was set. Silent success on a cancelled job is about the worst failure shape there is.

Moving from a deny-list (== "error" raises) to an allow-list (!= "success" raises) is the right correction, and it is what makes unknown statuses fail loudly rather than being read as success — the general form of the bug rather than just the reported instance.

The stray error yield sitting outside the if/elif chain was worth catching too. In practice the triggerer consumes the first event and closes the generator, so it was probably latent rather than live, but it was plainly wrong.

I checked the thing most likely to break under the new allow-list: execute_complete dereferences event["message"] for every non-success event. Every branch of this trigger — success, cancelled, both error paths, and the exception handler — sets message, so that is safe.

One small inconsistency, worth a follow-up rather than holding this: the validator checks status but not message, and message is exactly what the caller dereferences next. A custom or version-skewed trigger emitting {"status": "cancelled"} alone would KeyError — precisely the "crash opaquely" failure the validator exists to prevent. event.get("message", event) at the raise site would close it.

I have added a note to the provider changelog rather than letting this land silently. Dags whose batches get cancelled will now fail where they previously went green, and that is worth operators reading before they upgrade, even though the earlier green runs produced no output.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

@potiuk
potiuk force-pushed the add-validate-trigger-events-openai-deferrable-tasks branch from 9471e40 to b0ca49d Compare August 1, 2026 15:32
A deferred batch that was cancelled previously completed successfully
with no results, so operators upgrading need to know their tasks will
start failing where they used to go green.
@potiuk
potiuk force-pushed the add-validate-trigger-events-openai-deferrable-tasks branch from b0ca49d to 8a8d3d2 Compare August 1, 2026 16:48
@potiuk
potiuk merged commit 4b9c3b5 into apache:main Aug 1, 2026
79 checks passed
@takayoshi-makabe
takayoshi-makabe deleted the add-validate-trigger-events-openai-deferrable-tasks branch August 2, 2026 03:40
jason810496 pushed a commit that referenced this pull request Aug 2, 2026
Two PRs merged three hours apart on 2026-08-01 collided semantically:
#69506 added a test using the class attribute END_TIME, and #69534
renamed that attribute to LEGACY_END_TIME while branched off a main
that predated #69506. Git merged both cleanly, so the dangling
reference reached main unnoticed and every job that collects the
OpenAI provider tests now fails.

The case asserts that a terminal batch emits exactly one event, which
has nothing to do with the deprecated wall-clock deadline, so it moves
to the timeout constant that the rest of the behavioural cases use
rather than to LEGACY_END_TIME. The end_time path stays covered by
test_serialization_with_legacy_end_time.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants