fix: treat a blank project/domain as unset (FLYTE-SDK-3A) - #1444
Conversation
|
Self-review follow-up — pushed 07bb579, please read this before reviewing the diff. The first commit had a regression. Normalizing the blank inside Two consequences: secret listings silently change scope, and Fix: only a value typed on the command line is ambiguous, so the normalization moves to a click Verified with a scratchpad repro exercising
|
`flyte run --project "$PROJECT" --domain "$DOMAIN"` with unset shell variables hands the CLI empty strings. `CLIConfig.init` only fell back to the config file on `None`, so the blank values overrode it, and `require_project_and_domain` -- the guard that exists precisely to catch this -- checked `is None` and let them through. The blank project then reached CreateUploadLocation, where the backend answered "failed to validate project: invalid_argument: id is required". That surfaced as a RuntimeSystemError and was reported to Sentry as an SDK crash rather than as the user's missing configuration. Two halves: - `CLIConfig.init` now treats a blank --project/--domain as not provided and falls back to the config file, matching what `init_from_config` already does with `project or cfg.task.project` and what the config layer's `set_if_exists` does. - `require_project_and_domain`, `current_project` and `current_domain` reject blank as well as None, so when nothing supplies a project the user gets the existing user-kind InitializationError (filtered from Sentry) instead of an opaque backend error. fixes FLYTE-SDK-3A Signed-off-by: Haytham Abuelfutuh <haytham@afutuh.com>
Follow-up to the previous commit, which normalized the blank inside `CLIConfig.init`. That was too low in the stack: `flyte get secret`, `flyte create secret` and `flyte delete secret` all call `init` with a literal empty project/domain to select the *org-level* scope, and the normalization rewrote it to None, which then fell back to the config file. The listing would have silently changed scope, and `--cluster-pool` would have started failing outright, since `Secret._resolve_scope` rejects a request that carries both a cluster pool and a project/domain. Only a value typed on the command line is ambiguous, so the normalization moves to a click callback on the shared PROJECT/DOMAIN options (and on the two `flyte rerun` declares itself, which bypass those). A caller that passes project="" in Python now means it. fixes FLYTE-SDK-3A Signed-off-by: Haytham Abuelfutuh <haytham@afutuh.com>
07bb579 to
198bd00
Compare
What
flyte run --project "$PROJECT" --domain "$DOMAIN"with unset shell variables hands the CLI empty strings. Two things then went wrong:CLIConfig.initusedproject if project is not None else self.config.task.project, so a blank value overrode the config file instead of falling back to it.require_project_and_domain— the guard that exists precisely to catch a missing project — checkedcfg.project is None, so the blank sailed straight through.The blank project then reached
CreateUploadLocation, where the backend answeredfailed to validate project: invalid_argument: id is required. That came back as aRuntimeSystemErrorand was reported to Sentry as an SDK crash rather than as the user's missing configuration.The Sentry event shows the shape exactly — note both project and domain are empty, which is what you get from
-p "$P" -d "$D"with both unset:The fix
Both halves, because either alone leaves a bad outcome:
CLIConfig.inittreats a blank--project/--domainas not provided and falls back to the config file. This matches whatinit_from_configalready does (project or cfg.task.project) and what the config layer'sset_if_existsalready does (it filters empty strings out ofTaskConfig.auto). Without this half, the common case — a CI script with an unset variable — still fails when it should have just used the config file.require_project_and_domain,current_project,current_domainreject blank as well asNone. Without this half, a user with nothing configured anywhere still gets the opaque backend error. With it they get the existingInitializationError("ProjectNotConfigured", "user", ...), which is on_is_user_error's allow-list and so is filtered out of Sentry.The shared
blank_to_nonehelper also strips surrounding whitespace, somy-projectkeeps working rather than becoming a new failure mode.I deliberately left the in-cluster
tctx.action.projectpath incurrent_projectalone — it is populated by the backend, there is no Sentry evidence for it, and widening the change there would mask rather than surface a backend problem.Verification
20 of the new tests fail on
origin/mainand pass here (the remainder are regression guards for behavior that must not change — explicit values still override the config file).Full
tests/flyteis identical to the clean-origin/mainbaseline in this sandbox: 3597 passed, 7 failed on both sides, the 7 being the known pre-existing local failures (test_ls_files_loaded_modules_*,test_image_with_secrets,test_retrieve_degrades_when_keyring_not_installed, the twotest_launch_remote_*,test_real_build).tests/cli+tests/user_api+tests/flyte/config: 999 passed.ruff format/check,check_docstring_style.py(491 files clean) andmypyall clean.fixes FLYTE-SDK-3A
Sentry: https://unionai.sentry.io/issues/7491437173/
Note on the Sentry grouping
FLYTE-SDK-3Ais a mixed group: Sentry buckets everything that crashes at the same_upload_single_fileelse-branch, so its 9 events are four unrelated root causes:failed to validate project: invalid_argument: id is required302 FoundHTML pagepermission denied(org/identity)cross org calls are not allowedThis PR fixes only the first, which is the only shape still firing and the only one on a current release. The other three are aged out and are not SDK bugs. I've kept
fixes FLYTE-SDK-3Aso the group gets marked resolved-in-next-release; if one of the other shapes recurs, Sentry's regression detection will reopen it.