Repository navigation
Fix airflowctl tracebacks on an unusable credentials file - #72468
Eason09053360 wants to merge 1 commit into
Conversation
Reading the credentials file guarded only against the file being absent, so anything else about it that stopped a command - wrong permissions, non-UTF-8 bytes, truncated JSON, the wrong shape - reached the operator as a Python stack trace. `$AIRFLOW_HOME/production.json` is a generic enough name in a shared directory that a foreign or half-written file is not far-fetched, and none of those errors were something the CLI's own handler recognised. The tolerance that lets `auth login` run without a credentials file now covers an unusable one too, so the recovery the message recommends is actually available.
dec5228 to
c16f3a4
Compare
|
Hello @Eason09053360 - thank you for your contributions to Apache Airflow! The Airflow community has introduced a limit of 5 open pull requests at a time for contributors without write access to the repository. You currently have 33 open pull requests, so - as a one-time step of introducing the limit - we closed the ones where maintainers have not engaged yet:
These pull requests stay open because maintainers are already engaged in them - they count towards your limit:
This is not a judgement of you or of your changes. We never told contributors before that opening many pull requests at once was a problem, so there is nothing to feel bad about - and nothing is lost: your branches, commits and the review history stay where they are. What we ask you to do is to make your first prioritization decision: choose which of the pull requests above matter most to you, and reopen them (up to 5 open at a time, including the ones still open) with the "Reopen pull request" button or While your pull requests are waiting for review, the most valuable thing you can do is help in other ways - reviewing other contributors' pull requests, helping with issues, and taking part in the discussions on the devlist and Slack. Why we introduced the limit, what it means for you and how to reopen or restore a pull request is explained in https://github.com/apache/airflow/blob/main/contributing-docs/32_open_pull_request_limit.rst. Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting |
Why
Credentials.load()guarded only against the credentials file being absent. Every other way that file can be unusable reached the operator as a stack trace, becausesafe_call_commandrecognises none of those exception types:PermissionErrorUnicodeDecodeErrorJSONDecodeErrorTypeErrorapi_urlkeyKeyError: 'api_url'$AIRFLOW_HOME/production.jsonis a generic name in a shared directory, so a foreign or half-written file is not far-fetched. The traceback was also a dead end: the fix is to log in again, butauth loginloads the same file and failed the same way, leaving deleting the file by hand as the only way out.What
_read_cli_config(path)inairflow-ctl/src/airflowctl/api/client.pytakes over the open and the parse, which is what puts all of those cases in one place —OSErrorfor unreadable paths,ValueErrorfor both malformed JSON and non-UTF-8 bytes (siblings, not parent and child), plus an explicit check that the parsed result is a JSON object with anapi_url. They raiseAirflowCtlCredentialInvalidException, a newAirflowCtlExceptionsubclass.FileNotFoundErroris re-raised untouched so callers keep handling an absent file as the distinct case it is, and the debug-credentials read goes through the same helper.load()extends the tolerance it already had for a missing file to an unusable one, soauth login— the recovery the message recommends — can run and replace it.safe_call_commandcatchesAirflowCtlExceptionrather than a hand-maintained tuple of subclasses. The tuple was already equivalent to the base class, and keeping it manual means the next exception class added anywhere regresses to a traceback, which is the failure this PR is fixing. One side effect: the path-traversal guard in_safe_path_under_airflow_homeraisesAirflowCtlExceptiondirectly and so was not caught before; it now renders as a message.Tests cover each of the file states above and that
AUTH/NO_AUTHclients still load past an unusable file.Deliberately out of scope:
{"api_url": null}still loads asNoneand letsget_clientfall back tolocalhost:8080. That is a silently-wrong-server bug rather than a traceback,Credentials.save()itself writes such a file, and an existing test pins the current behaviour — it wants its own change.auth list-envsalso reads the same file through its own logic, which now defines "unusable" slightly differently.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5) following the guidelines