Skip to content

Stop one malformed provider from breaking discovery for all providers - #72854

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:provider-discovery-resilience
Sep 10, 2026
Merged

kaxil merged 1 commit into
apache:mainfrom
astronomer:provider-discovery-resilience

Conversation

@kaxil

@kaxil kaxil commented Sep 10, 2026 •

Copy link
Copy Markdown
Member

Summary

One installed provider whose metadata this Airflow version does not recognise currently takes down provider discovery for every provider in the process, not just its own entry.

provider_schema_validator.validate(provider_info) sits unwrapped inside the entry-point loop, and nothing up either call chain catches it. grep -c ValidationError returns 0 in both providers_manager.py and providers_manager_runtime.py. The consequences:

  • Every provider after the offender in entry-point order is never registered.
  • initialize_providers_list() raises.
  • provider_info_cache does not memoise failures, so it raises again on every subsequent access rather than settling into a degraded state.
  • Both entry points share this loop: the scheduler, API server and dag-processor via airflow-core/src/airflow/providers_manager.py, and workers via task-sdk/src/airflow/sdk/providers_manager_runtime.py.

With [core] lazy_discover_providers = False, discovery also runs from the eager-init block in airflow/__init__.py, so import airflow itself raises. That setting defaults to True, so the usual reach is the first access to the providers manager rather than import time.

It also contradicts the documented contract

The docstring on the very function doing the validation says the runtime schema is deliberately the lenient one:

Note that the schema is different at runtime than provider.yaml.schema.json. The development version of provider schema is more strict and changes together with the code. The runtime version is more relaxed (allows for additional properties) and verifies only the subset of fields that are needed at runtime.

A schema violation aborting all discovery is the opposite of relaxed. #71104 declined to tighten this same runtime schema for exactly this reason, and #72853 initially added a pattern to it before backing that out on the same grounds. The fragility is what makes those tightenings unsafe, so removing it also unblocks legitimate schema work later.

What changes

The offending provider is logged with its package name and skipped; the rest load normally. The scope of the try is the single validate() call, so the package-name mismatch check below it still fails loudly, since that is a packaging error rather than unusable metadata.

Only jsonschema.ValidationError is caught. A SchemaError or UnknownType means the schema itself is broken rather than any provider, and _create_provider_info_schema_validator never calls check_schema, so such a defect surfaces lazily inside this loop. Catching it here would emit one "provider does not conform" warning per installed provider, register nothing, and name the wrong component, replacing a single loud failure with N misleading ones.

A second, closely related hole is fixed alongside it. package-name is not in the runtime schema's required list, so validate() passes for metadata that omits it and the subscript below then raised an uncaught KeyError -- the same "one provider aborts discovery for all" failure this PR exists to remove. It gets the same warn-and-skip.

Not addressed here

entry_point.load()() on the line above is also unwrapped, so a provider that raises while producing its own metadata still aborts discovery the same way. That is a different failure mode with a different judgement call about whether an unloadable provider should be visible or silent, so it is left alone rather than folded in.

On the tests

The three cases drive the real schema validator rather than a mock, so they cannot be satisfied by catching an exception type jsonschema never raises. Against apache/main the first two fail (ValidationError escaping discovery, and KeyError: 'package-name'), while the third passes and must keep passing: it asserts a SchemaError still propagates, and it fails against a broad except Exception, which is what pins the narrow catch.

@kaxil
kaxil force-pushed the provider-discovery-resilience branch from e18036f to 29e7096 Compare September 10, 2026 01:05
`provider_schema_validator.validate()` was called unwrapped inside the entry-point
loop in provider discovery, and nothing up either call chain caught it. A single
installed provider whose metadata fails validation therefore took down the whole
provider list rather than just its own entry: every provider after it in entry-point
order was never registered, `initialize_providers_list()` raised, and because
`provider_info_cache` does not memoise failures it raised again on every subsequent
access. Both the scheduler/API-server path and the worker path in the Task SDK share
this loop.

Only `jsonschema.ValidationError` is caught. A `SchemaError` or `UnknownType` means
the schema itself is broken rather than the provider, and swallowing those would
report one "provider does not conform" warning per installed provider while naming
the wrong component.

`package-name` is not in the runtime schema's required list, so validation passing
did not guarantee it was present and the subscript below could still raise an
uncaught `KeyError`. That is now the same warn-and-skip. The package-name mismatch
check stays fatal, since that is a packaging error rather than unusable metadata.
@kaxil
kaxil force-pushed the provider-discovery-resilience branch from 29e7096 to def5cd6 Compare September 10, 2026 11:39
@kaxil
kaxil marked this pull request as ready for review September 10, 2026 13:35
@kaxil
kaxil merged commit 2c2dcce into apache:main Sep 10, 2026
108 checks passed
@kaxil
kaxil deleted the provider-discovery-resilience branch September 10, 2026 13:47
@potiuk

potiuk commented Sep 10, 2026

Copy link
Copy Markdown
Member

Should we backport it to 3.3.2 ?

imrichardwu pushed a commit to imrichardwu/airflow that referenced this pull request Sep 11, 2026
…apache#72854)

`provider_schema_validator.validate()` was called unwrapped inside the entry-point
loop in provider discovery, and nothing up either call chain caught it. A single
installed provider whose metadata fails validation therefore took down the whole
provider list rather than just its own entry: every provider after it in entry-point
order was never registered, `initialize_providers_list()` raised, and because
`provider_info_cache` does not memoise failures it raised again on every subsequent
access. Both the scheduler/API-server path and the worker path in the Task SDK share
this loop.

Only `jsonschema.ValidationError` is caught. A `SchemaError` or `UnknownType` means
the schema itself is broken rather than the provider, and swallowing those would
report one "provider does not conform" warning per installed provider while naming
the wrong component.

`package-name` is not in the runtime schema's required list, so validation passing
did not guarantee it was present and the subscript below could still raise an
uncaught `KeyError`. That is now the same warn-and-skip. The package-name mismatch
check stays fatal, since that is a packaging error rather than unusable metadata.
xvega pushed a commit to xvega/airflow that referenced this pull request Sep 13, 2026
…apache#72854)

`provider_schema_validator.validate()` was called unwrapped inside the entry-point
loop in provider discovery, and nothing up either call chain caught it. A single
installed provider whose metadata fails validation therefore took down the whole
provider list rather than just its own entry: every provider after it in entry-point
order was never registered, `initialize_providers_list()` raised, and because
`provider_info_cache` does not memoise failures it raised again on every subsequent
access. Both the scheduler/API-server path and the worker path in the Task SDK share
this loop.

Only `jsonschema.ValidationError` is caught. A `SchemaError` or `UnknownType` means
the schema itself is broken rather than the provider, and swallowing those would
report one "provider does not conform" warning per installed provider while naming
the wrong component.

`package-name` is not in the runtime schema's required list, so validation passing
did not guarantee it was present and the subscript below could still raise an
uncaught `KeyError`. That is now the same warn-and-skip. The package-name mismatch
check stays fatal, since that is a packaging error rather than unusable metadata.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants