Skip to content

air: Stop showing Max Retries 0 when runs/get omits the retry limit - #7623

Draft
artemy-kolesnikov wants to merge 4 commits into
mainfrom
CNXT-2613-max-retries-na
Draft

artemy-kolesnikov wants to merge 4 commits into
mainfrom
CNXT-2613-max-retries-na

Conversation

@artemy-kolesnikov

@artemy-kolesnikov artemy-kolesnikov commented Nov 13, 2026 •

Copy link
Copy Markdown

Title: air: Stop showing Max Retries 0 when runs/get omits the retry limit

Changes

air get (and the air list info pane) showed Max Retries 0 for AI Runtime runs whatever retry limit they were submitted with. Jobs runs/get leaves max_retries out of every task run, and SDK v0.197.0 decodes the missing field as 0. maxRetries(run) in cmd/air/format.go printed that 0.

resolveMaxRetries(run, configRaw) now applies these rules in order:

Case Shown
runs/get carries max_retries on the latest task (presence via the SDK's ForceSendFields, so an explicit 0 counts) the server value (unlimited for -1)
Not a SUBMIT_RUN (for example a bundle job deployed with air convert-to-dabs, whose limit lives in the job settings) N/A
Submit run whose uploaded config sets max_retries that value, e.g. 1
Submit ai_runtime_task run whose config leaves it unset 3 (CLI default)
Legacy gen_ai_compute_task run with no explicit value, multi-container run (no deployment command_path, so no config path), config missing or unreadable or unparsable N/A
  • The config is the one air get already downloads for the Configuration box. resolveConfigYAML / configYAML now also return the raw bytes, so there is no extra request. Only the max_retries key is decoded, leniently, so configs from other CLI versions still parse.
  • air list's info pane now runs the same ai_runtime_task enrichment as air get (same guard), so it shows the config box, accelerators and the same Max Retries value instead of N/A.
  • resolveMaxRetries returns the limit and its source (reported / configured / cli_default) so air get -o json can expose the same value later. JSON output is unchanged in this PR.
  • Changelog fragment: .nextchanges/air/get-max-retries.md.

Why

A supervising agent couldn't tell whether a failed workload would be retried: help says the default is 3, the run used 3, and air get said 0. The submit-message half of the report ("Failed attempts will be retried up to 3 times.") was already removed by #7270.

Why the default is assumed only for ai_runtime_task submit runs:

  • The Go CLI only emits ai_runtime_task, and runsubmit.go always sends max_retries (ForceSendFields), defaulting to defaultMaxRetries = 3. The Python CLI defaulted to 3 before it first emitted ai_runtime_task.
  • Legacy gen_ai_compute_task runs may predate the Python CLI's switch from 0 to 3 (2026-05-22), and nothing on the run records which version submitted it, so an unset value is unknown.
  • Job runs take their retries from the job's task settings. A user can edit max_retries in databricks.yml after convert-to-dabs, so the synced training_config.yaml can be stale.

Rejected:

  • Wide scope: read jobs/get settings for job runs and search bundle deployment directories for configs. More code and risk for a less common path. Job runs show N/A here; see follow-ups.
  • Always show 3 when unset: gives a false 3 for older legacy runs and for job runs whose settings differ.
  • Server value only (N/A when missing): ignores the config the CLI already downloads, and the ticket asks for the budget to be shown.
  • Use the SDK's 0 as-is: the bug.

Tests

  • TestMaxRetries (15 cases): config 1 / 0 / -1, unset → 3 (CLI default), no config, unparsable config, legacy unset → N/A, legacy explicit 2, job run with and without a config → N/A, unknown run type → N/A, server 0 over a config of 2, server 5 on a job run, server -1, no tasks.
  • TestResolveMaxRetriesSource: the source each case reports.
  • TestMaxRetriesFromDecodedRunGet: decodes real runs/get response bodies captured from a workspace through the SDK. Absent key + config 1 → 1; absent key + unset → 3 (CLI default); multi-container body → no config path, N/A; Python-shaped legacy body → N/A; explicit "max_retries": 0 → 0.
  • TestRunDetailTextReadsTheUploadedConfig (list pane, httptest): configured 1, unset 3 (CLI default), config download 404 → N/A, job run → N/A.
  • With resolveMaxRetries swapped back to the old behaviour (read the SDK field, 0 when absent), 11 of 15 TestMaxRetries cases, TestMaxRetriesFromDecodedRunGet and all 4 list-pane cases fail. The 4 that still pass are the 3 server-reported cases and config 0, where the old 0 is right by coincidence.
  • Acceptance: air/get and air/get-ai-runtime no longer seed "max_retries": 3 on the fake task (the real API never returns it) and now set "run_type": "SUBMIT_RUN". get-ai-runtime adds a second case that re-imports a config with max_retries: 1. Goldens: get → N/A (legacy, unset), get-ai-runtime → 3 (CLI default) then 1. With the old code these fixtures fail (0 in all three places).
  • go test ./cmd/air/... -count=1 passes. go test ./acceptance -run 'TestAccept/air/' passes (20 fixtures). ./task lint-q-go-root (0 issues), ./task fmt-q-go, ./task deadcode (no dead code), ./task check-changelog and gofmt are clean.

Manual verification (against a workspace)

NO_COLOR=1 databricks air get <run>, base build vs this change:

Run Config Base Fixed
a failed run, retried once (attempts 0 and 1) max_retries: 1 Max Retries 0 Max Retries 1
a failed run, attempt 0 only max_retries: 0 Max Retries 0 Max Retries 0
a run submitted for this test, then cancelled unset Max Retries 0 Max Retries 3 (CLI default)
another user's run, config not readable unknown Max Retries 0 Max Retries N/A
  • Raw runs/get for the submitted run has run_type: SUBMIT_RUN, and its task keys contain no max_retries.
  • air get -o json returns the same keys with both builds.

Follow-ups (not in this PR)

  • air get -o json should expose max_retries. Call resolveMaxRetries and report the source as data (reported / configured / cli_default / null) rather than as a suffix. JSON mode would also need to download the config, which it doesn't today.
  • Job runs: read jobs/get(job_id) settings.tasks[task_key].max_retries, labelled as the current job settings.
  • Multi-container runs: derive the config path from containers[].command_path. The SDK's DeploymentSpec doesn't decode containers yet, so this needs a raw read or an SDK bump.
  • Jobs: runs/get doesn't echo max_retries / retry_on_timeout / min_retry_interval_millis on task runs, although the API model documents max_retries there.

This pull request and its description were written by Isaac.

Jobs runs/get leaves max_retries out of every task run, and the SDK decodes
the missing field as 0, so `air get` and the `air list` info pane showed
"Max Retries 0" even for runs submitted with the default of 3 or an explicit
limit .

The server value is now used only when the response carries the key. For a
one-time submit run, the limit is read from the run's uploaded training
config: the configured value when it sets max_retries, and "3 (CLI default)"
for ai_runtime_task runs that leave it unset, since the CLI always submits
its default. Job runs, multi-container runs, legacy gen_ai_compute_task runs
with no explicit value, and runs whose config can't be read show N/A.

The derivation is resolveMaxRetries, which returns the limit and its source
so `air get -o json` can expose the same value later.

Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions github-actions Bot added the AIR Databricks AI Runtime CLI label Nov 13, 2026
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Commit: 9186e20d4 | Workflow run

Regression test report

Selected 2 changed tests (limit=20, 0 not selected)

2 tests: regression=2 unreleased=0 coverage=0 failing=0
test branch main (c4559ed) latest (v1.26.0)
TestAccept/air/get ✅ ❌ ❌
TestAccept/air/get-ai-runtime ✅ ❌ ❌
TestAccept/air/get: branch ✅ | main (c4559ed) ❌ | latest (v1.26.0) ❌

main (c4559ed):

acceptance_test.go:1374: Diff:
        --- air/get/output.txt
        +++ /tmp/TestAcceptairget3095561147/002/output.txt
        @@ -22,7 +22,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   N/A                                             │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │

latest (v1.26.0):

acceptance_test.go:1374: Diff:
        --- air/get/output.txt
        +++ /tmp/TestAcceptairget3760500579/002/output.txt
        @@ -22,7 +22,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   N/A                                             │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │
        @@ -49,7 +49,7 @@
             "attempt_number": 0,
             "experiment_name": "my-exp",
             "dashboard_url": "[DATABRICKS_URL]/jobs/runs/123?o=[WORKSPACE_ID]",
        -    "mlflow_url": "[DATABRICKS_URL]/ml/experiments/exp1/runs/run1/logs",
        +    "mlflow_url": "[DATABRICKS_URL]/ml/experiments/exp1/runs/run1/artifacts/logs/node_0",
             "est_remaining_seconds": null,
             "est_percent_complete": null
           }
TestAccept/air/get-ai-runtime: branch ✅ | main (c4559ed) ❌ | latest (v1.26.0) ❌

main (c4559ed):

acceptance_test.go:1374: Diff:
        --- air/get-ai-runtime/output.txt
        +++ /tmp/TestAcceptairget-ai-runtime4265071125/002/output.txt
        @@ -22,7 +22,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   3 (CLI default)                                 │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │
        @@ -76,7 +76,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   1                                               │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │
        
    acceptance_test.go:1152: LOG.import: 
    acceptance_test.go:1152: LOG.import-max-retries: 
    acceptance_test.go:1152: LOG.mkdirs: 
FAIL

latest (v1.26.0):

acceptance_test.go:1374: Diff:
        --- air/get-ai-runtime/output.txt
        +++ /tmp/TestAcceptairget-ai-runtime1803479718/002/output.txt
        @@ -22,7 +22,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   3 (CLI default)                                 │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │
        @@ -49,7 +49,7 @@
             "attempt_number": 0,
             "experiment_name": "my-exp",
             "dashboard_url": "[DATABRICKS_URL]/jobs/runs/123?o=[WORKSPACE_ID]",
        -    "mlflow_url": "[DATABRICKS_URL]/ml/experiments/exp1/runs/run1/logs",
        +    "mlflow_url": "[DATABRICKS_URL]/ml/experiments/exp1/runs/run1/artifacts/logs/node_0",
             "est_remaining_seconds": null,
             "est_percent_complete": null
           }
        @@ -76,7 +76,7 @@
         │  Status        ● SUCCESS                                       │
         │  Submitted     2023-11-14 22:13 UTC                            │
         │  Retries       0                                               │
        -│  Max Retries   1                                               │
        +│  Max Retries   0                                               │
         │  Duration      12s                                             │
         │  Experiment    my-exp                                          │
         │  MLflow Run    my-run                                          │
        
    acceptance_test.go:1152: LOG.import: 
    acceptance_test.go:1152: LOG.import-max-retries: 
    acceptance_test.go:1152: LOG.mkdirs: 
FAIL

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Integration test report

Commit: 9186e20

Run: 43530694590

Env 💚​RECOVERED ✅​pass 🙈​skip Time
💚​ aws linux-2core-8gb 1 270 17 6:20
💚​ aws-windows-latest-4core-16gb 1 272 15 4:21
💚​ azure linux-2core-8gb 1 269 17 4:42
💚​ azure-windows-latest-4core-16gb 1 271 15 3:32
💚​ gcp linux-2core-8gb 1 270 17 4:49
💚​ gcp-windows-latest-4core-16gb 1 272 15 3:57
Test Name aws linux-2core-8gb aws-windows-latest-4core-16gb azure linux-2core-8gb azure-windows-latest-4core-16gb gcp linux-2core-8gb gcp-windows-latest-4core-16gb
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 3 slowest tests (at least 2 minutes):
duration env testname
3:27 aws-windows-latest-4core-16gb TestAccept
3:24 azure-windows-latest-4core-16gb TestAccept
3:16 gcp-windows-latest-4core-16gb TestAccept

artemy-kolesnikov and others added 3 commits November 13, 2026 23:48
Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AIR Databricks AI Runtime CLI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants