Skip to content

Suggest "did you mean ...?" for unknown key lookups and variable references - #6208

Merged
Sankalp-Mittal merged 15 commits into
mainfrom
sankalp-mittal/did-you-mean-variable-interpolation
Aug 14, 2026
Merged

Suggest "did you mean ...?" for unknown key lookups and variable references#6208
Sankalp-Mittal merged 15 commits into
mainfrom
sankalp-mittal/did-you-mean-variable-interpolation

Conversation

@Sankalp-Mittal

@Sankalp-MittalSankalp-Mittal commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Changes

When a ${...} variable reference fails to resolve, the error now lists the closest matching keys (edit distance ≤ 2) as full drop-in replacement references — each on its own line, with only the failed path segment swapped:

Error: reference does not exist: ${var.hst}
did you mean:
${var.host}

Multiple candidates use did you mean one of::

Error: reference does not exist: ${var.hst}
did you mean one of:
${var.host}
${var.hosts}

Only the failed segment is corrected; the prefix and the rest of the path are preserved, so nested and indexed references reconstruct correctly:

  • ${var.clustr.spark_version}${var.cluster.spark_version} (outer key)
  • ${var.cluster.spark_versio}${var.cluster.spark_version} (leaf)
  • ${var.librariez[0].jar}${var.libraries[0].jar} (index preserved)

Implementation

The suggestion logic lives in libs/dyn/suggest.go:

  • levenshteinDistance — edit distance between two strings.
  • suggestKeys — keys of a Mapping within maxSuggestionDistance (2) of the missing key, sorted by increasing distance (ties keep insertion order).
  • didYouMean — single-line clause (, did you mean "x"?) used by the generic key-lookup error.
  • didYouMeanReferences / replaceKey — build the multi-line drop-in block, rebuilding each reference from the original text via Path.String() (so index components survive).

noSuchKeyError carries the suggestions, computed in pathComponent.visit where the parent map is in scope. Variable interpolation in libs/dyn/dynvar rewrites the not-found message and discards the original error, so it re-attaches the drop-in block via the exported dyn.DidYouMeanReferences(err, reference), passing the original (pre-rewrite) reference text.

Scope

Because the underlying key lookup is generic, suggestions are drawn from the siblings at the level where the lookup fails, so this covers more than ${var.*}:

  • ${var.my_catlog} → other variable names
  • ${workspace.rooot_path} / ${bundle.naem} → sibling config fields

Behavior notes:

  • Only bundle, workspace, and variables prefixes are resolved at validate time; ${resources.*} references are left unresolved until deploy, so a typo there produces no suggestion.
  • With multiple typos across nesting layers, the lookup fails at the outermost missing key, so that segment is what gets suggested (e.g. ${var.clustr.spark_versio}${var.cluster.spark_versio}).
  • A wrong top-level prefix (e.g. ${wrkspace.host}) is skipped during resolution and never reaches a key lookup, so no suggestion is produced.
  • The generic dyn.GetByPath key-not-found error keeps a single-line bare-key hint (key not found at "baz", did you mean "bar"?), since there is no ${...} reference to rebuild there.

Why

A mistyped variable reference in databricks.yml (e.g. ${var.my_catlog} instead of ${var.my_catalog}) previously failed with a bare reference does not exist: ${var.my_catlog} and no hint, even though the CLI knows every valid key at the point of failure. The CLI already offers this for mistyped command-line flags; this brings the same guidance to variable interpolation, and — because the hint is attached at the generic dyn layer — to every not-found key lookup. Rendering suggestions as full drop-in references makes them explicit and copy-pasteable.

Suggestions are shown only when a candidate is within edit distance 2; otherwise the error is unchanged, so unrelated typos don't produce noisy or misleading hints.

Tests

  • libs/dyn/suggest_test.golevenshteinDistance, suggestKeys (distance threshold, ordering, empty map), didYouMean, and DidYouMeanReferences (single, multiple, nested outer/leaf typo, index component, non-var prefix, no suggestions, fallback).
  • libs/dyn/visit_get_test.go — a close key produces a suggestion; a far-off key produces none.
  • libs/dyn/dynvar/resolve_test.goTestResolveNotFoundSuggestsCloseKey asserts the hint flows through variable interpolation.
  • acceptance/bundle/variables/reference-typo/ — six scenarios capturing exact CLI output: single suggestion, multiple suggestions, non-var (workspace) multiple, multiple typos where only the first is reported, two typos in one reference (outermost wins), and a double-nested typo with multiple suggestions.

This pull request and its description were written by Isaac.

@Sankalp-MittalSankalp-Mittal changed the title Sankalp mittal/did you mean variable interpolationSuggest "did you mean ...?" for unknown key lookups and variable referencesAug 10, 2026
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: e6c54ea

Run: 31793733212

Env🟨​KNOWN💚​RECOVERED🙈​SKIP✅​pass🙈​skipTime
💚​aws linux4428611454:15
💚​aws windows4428811435:32
🟨​azure linux31428511456:46
🟨​azure windows31428711436:14
💚​gcp linux1528611454:48
💚​gcp windows1528811435:00
8 interesting tests: 4 SKIP, 3 KNOWN, 1 RECOVERED
Test Nameaws linuxaws windowsazure linuxazure windowsgcp linuxgcp windows
💚​TestAccept💚​R💚​R💚​R💚​R💚​R💚​R
🙈​TestAccept/bundle/invariant/no_drift🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/ssh/connection🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🟨​TestFetchRepositoryInfoAPI_FromRepo💚​R💚​R🟨​K🟨​K🙈​S🙈​S
🟨​TestFetchRepositoryInfoAPI_FromRepo/root💚​R💚​R🟨​K🟨​K
🟨​TestFetchRepositoryInfoAPI_FromRepo/subdir💚​R💚​R🟨​K🟨​K
Top 3 slowest tests (at least 2 minutes):
durationenvtestname
5:22aws windowsTestAccept
4:23gcp windowsTestAccept
3:22azure windowsTestAccept

@Sankalp-Mittal
Sankalp-Mittal marked this pull request as ready for review August 10, 2026 10:30
Comment threadacceptance/bundle/variables/reference-typo/databricks.yml Outdated
Comment threadacceptance/bundle/variables/reference-typo/script Outdated
@@ -0,0 +1,13 @@

>>> errcode [CLI] bundle validate
Error: reference does not exist: ${var.hst}, did you mean "host"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

seems ambiguous, maybe the suggestion can be more of a drop-in replacement?

Suggested change
Error: reference does not exist: ${var.hst}, did you mean "host"?
Error: reference does not exist: ${var.hst}, did you mean ${var.host}?

@Sankalp-MittalSankalp-MittalAug 13, 2026

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

This would get confusing where there are more than one suggestions, especially for long variable names with multiple layers of nesting

@Sankalp-MittalSankalp-MittalAug 13, 2026

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We could write something like

Error: reference does not exist: ${var.hst}, did you mean "host" in place of "hst"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

+1 for having the full replacement. Those error messsage more explicit and easier to copy paste.

This would get confusing where there are more than one suggestions, especially for long variable names with multiple layers of nesting

Could you elaborate or give an example?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

especially for long variable names with multiple layers of nesting

This is interesting - can you please add an acceptance test for multiple layers to capture behaviour? E.g. how do you resolve

resources:
jobs:
nightly:
${resources.jobbs.nightlyy}

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

This is interesting - can you please add an acceptance test for multiple layers to capture behaviour? E.g. how do you resolve

This would just reply with the first error since as soon as we find an error we stop resolving variable names. Added the test double-nested-typo

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

+1 for having the full replacement. Those error messsage more explicit and easier to copy paste.

This would get confusing where there are more than one suggestions, especially for long variable names with multiple layers of nesting

Could you elaborate or give an example?

Actually after thinking some more about this I agree. I'll add the recommendations in seperate lines instead of in one line should make it much cleaner

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you can use libs/diag for the errors, it allows you to pass extra context

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I didn't need to use libs/diag it worked without it as well

Comment threadacceptance/bundle/variables/reference-typo/databricks.yml Outdated
Comment threadlibs/dyn/suggest_test.go
Comment thread.nextchanges/cli/did-you-mean-variables.md Outdated
Comment threadlibs/dyn/suggest.go Outdated
if len(suggestions) > 1 {
header = "did you mean one of:"
}
return "\n\n" + header + "\n" + strings.Join(lines, "\n")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this is fragile and should not be done. libs/diag handles proper formatting of multi-line errors in various terminal environments & correct interleaving of messages.

since you can't import libs/diag inside libs/dyn, I suggest you propagate the suggestion upwards and handle it there

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Did the change

@Sankalp-Mittal
Sankalp-Mittalforce-pushed the sankalp-mittal/did-you-mean-variable-interpolation branch from b964d6c to 7d038a4CompareAugust 14, 2026 10:20
Propagate reference suggestions as structured data (dynvar.ReferenceError
+ dyn.SuggestedReferences) instead of formatting a multi-line error string
in libs/dyn. The mutator builds the diagnostic Detail so libs/diag owns
terminal formatting. Rendered output is unchanged.
Co-authored-by: Isaac

@janniklasrosejanniklasrose left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

Comment on lines +5 to +8
Error: reference does not exist: ${var.hst}

did you mean:
${var.host}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nice, this is now very clear and actionable!

Comment on lines +71 to +74
Error: reference does not exist: ${var.clustr.spark_versio}

did you mean:
${var.cluster.spark_versio}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this isn't great, but not much we can do since we fail fast and traversing the suggestion in search for valid references is probably overkill

@Sankalp-Mittal
Sankalp-Mittal added this pull request to the merge queueAug 14, 2026
Merged via the queue into main with commit 273b78fAug 14, 2026
28 checks passed
@Sankalp-Mittal
Sankalp-Mittal deleted the sankalp-mittal/did-you-mean-variable-interpolation branch August 14, 2026 11:28
deco-sdk-taggingBot added a commit that referenced this pull request Aug 20, 2026
## Release v1.13.0
### Notable Changes
* `bundle deploy` now reports the per-resource actions it took, how many files it synced, and a summary of created/changed/deleted/unchanged resources; `bundle destroy` reports how many resources it deleted. `-q` prints only the summaries, `-qq` only warnings and errors. ([#5720](#5720))
### CLI
* `databricks aitools install` now supports Goose, installing Databricks agent skills into its skills directory.
* Error messages for failed key lookups and variable references now suggest the closest matching key if one is found. ([#6208](#6208))
* Released binaries are now built against the FIPS 140-3 validated Go Cryptographic Module, with FIPS 140-3 mode enabled by default. TLS connections negotiate only FIPS-approved cipher suites, which drops ChaCha20 and CBC from what the client offers. FIPS mode can be disabled at startup with `GODEBUG=fips140=off`, which restores the previous TLS behaviour ([#6262](#6262)).
* `databricks environments setup-local` now removes a `databricks-connect` pin from `[project].dependencies`, an optional-dependency extra, or a dependency group when its version range conflicts with the compute target's `databricks-connect` version, so `uv sync` no longer fails with an unsatisfiable resolution when a template ships a conflicting pin. A pin that co-resolves, carries no version, or is marker-gated is left untouched, and each removed pin is reported with the new `W_DBCONNECT_CONSOLIDATED` warning. Wildcard version pins such as `==15.1.*` are now also checked for conflicts with the environment's constraints.
### Bundles
* Allow dashes in the catalog and schema names prompted by `databricks bundle init`, and backtick-quote the catalog and schema identifiers in the SQL generated by the built-in templates so names with dashes work at runtime.
* Fixed `bundle.git.branch`, `bundle.git.commit`, and `bundle.git.origin_url` being empty for bundles deployed from a workspace Git folder that has Git CLI access. The workspace API does not report git metadata for those folders, so it is now read from the Repos API instead.
* direct: job_runs deploy progress lines now include the resource key (e.g. `Output from job_runs.foo: id=123: ...`) so concurrent runs are easier to tell apart.
* direct: `resources.job_runs` can set `lifecycle.triggers.on_bundle_deploy: true` to re-fire the run on every bundle deploy. Removing the trigger does not recreate the existing run.
* When migrating a bundle to the direct deployment engine, resources that only the direct engine supports (e.g. instance pools, catalogs) are now skipped by the deploy that migrates the state instead of failing it. They are created by the next deploy, which runs on the migrated state.
* Warn on invalid `secret_scopes` permission levels (`READ`, `WRITE`, `MANAGE`); fail under `bundle validate --strict`.
* Reject secret scope permissions that name no principal, instead of failing after the scope is created.
* Write the deployment state atomically so an interrupted save cannot leave a state file that the CLI refuses to read.
* Warn when the deployment state was last written by a newer CLI version than the one running.
* Support pip extras (e.g. `[train]`) on local wheels in a job environment's `dependencies` ([#1602](#1602)).
### Dependency Updates
* Bump `github.com/databricks/databricks-sdk-go` from v0.170.0 to v0.171.0 ([#6320](#6320)).
* Bump the Databricks Terraform provider to 1.127.0 ([#6319](#6319)).
* Bump Go toolchain to 1.26.6 ([#6266](#6266)).
* Bump Go toolchain to 1.26.7 ([#6325](#6325)).
Sign up for freeto 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.

4 participants

@Sankalp-Mittal@eng-dev-ecosystem-bot@janniklasrose@shreyas-goenka