Skip to content

fix(add): fail fast with a clear error when a package isn't found - #2996

Open
mikeland73 wants to merge 2 commits into
mainfrom
mikeland73/missing-package-error-msg
Open

mikeland73 wants to merge 2 commits into
mainfrom
mikeland73/missing-package-error-msg

Conversation

@mikeland73

@mikeland73 mikeland73 commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2765.

devbox add inotifywait (a binary in inotify-tools, not a package) downloaded nixpkgs and ran nix search, then failed with a confusing error:

Ensuring nixpkgs registry is downloaded.
error: getting status of '/my/current/path/nixpkgs/bde0...': No such file or directory
Ensuring nixpkgs registry is downloaded: Fail

Error: Package inotifywait not found

Now it fails in about 0.4s without touching nixpkgs:

$ devbox add inotifywait
Error: Package "inotifywait" not found. To search for packages, use `devbox search inotifywait`

$ devbox add nodejs@99999
Error: Package "nodejs@99999" not found. To search for packages, use `devbox search nodejs`
  • Fast-fail only for bare devbox package names. If search returns not-found for a devbox package (not a flake ref) and its name (without version) has no ., return the error immediately. In a random sample of 150 of nixpkgs' ~24.8k top-level derivations, all 150 resolved in search, so the nixpkgs fallback wouldn't find these either.
  • Dotted attribute paths still fall back to nixpkgs. Search doesn't index alias sets (python3Packages.requests, beamPackages.hex), outputs (openssl.dev, gcc-unwrapped.lib) or stdenv.cc.cc.lib, and those work on main through the fallback. If the fallback also fails, the user gets the same message.
  • v1 resolver: FetchResolvedPackage reported every /v1/resolve error as ErrPackageNotFound, including network and server errors. It now does that only for a 404. The v2 resolver (the default) already behaved this way.

Test plan

Manual, with a locally built binary:

Input Result
inotifywait instant error with devbox search hint
nodejs@99999 instant error, hint is devbox search nodejs
stdenv.cc.cc.lib added (same as main)
openssl.dev added (same as main)
python3Packages.requests added (same as main)
foo.barbaz falls back to nixpkgs, then the new error
hello added as hello@latest
  • New unit test TestFetchResolvedPackageErrors: with both v1 and v2 resolvers, a 404 maps to ErrPackageNotFound and a 500 does not. It fails on main's v1 resolver.
  • New testscript testscripts/add/add_not_found.test.txt: devbox add inotifywait and devbox add hello@99999 fail with the new message and don't download nixpkgs.
  • go test ./testscripts/ -run TestScripts/add, all add* testscripts pass, including add.test.txt, which covers the stdenv.cc.cc.lib fallback
  • go test ./internal/devbox/... ./internal/lock/... ./internal/boxcli/...
  • golangci-lint run ./internal/devbox/... ./internal/lock/...: 0 issues

🤖 Generated with Claude Code

When the search service doesn't know a bare package name (e.g.
`devbox add inotifywait`), return an error that suggests `devbox search`
instead of downloading nixpkgs and running `nix search`, which is slow
and often fails with a confusing error.

Dotted attribute paths (stdenv.cc.cc.lib, openssl.dev,
python3Packages.requests) aren't all indexed by search, so those still
fall back to nixpkgs.

Also stop the v1 resolver from reporting network and server errors as
"package not found".

Fixes #2765

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikeland73

Copy link
Copy Markdown
Collaborator Author

@claude ptal

@claude

claude Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Claude finished @mikeland73's task in 23s —— View job


Review of #2996

The change is small and targeted, and the approach looks sound. I read the diff and the surrounding code. I did not build it or run the tests. I found one real issue and a few nits.

Issue: flake and non-devbox packages hit the new branch with an empty hint

internal/devbox/packages.go:136-143

CanonicalName() returns "" when !p.IsDevboxPackage (internal/devpkg/package.go:500-503). strings.Contains("", ".") is false, so any non-devbox package (flake ref, path:, etc.) whose validation returns ErrPackageNotFound now takes the fast-fail branch.

  • Before this PR, that case fell to !versionedPkg.IsDevboxPackage and propagated the original error.
  • Now the user gets Package "github:foo/bar#baz" not found. To search for packages, use devbox search ``, with an empty search term. A devbox search hint also doesn't apply to a flake ref.

Suggested fix: gate the new branch on versionedPkg.IsDevboxPackage, which is the same condition the next else if uses:

} else if errors.Is(err, nix.ErrPackageNotFound) &&
    pkg.IsDevboxPackage &&
    !strings.Contains(pkg.CanonicalName(), ".") {

Non-devbox packages then keep their existing behavior. If you'd rather keep the new message for them, packageNotFoundError should omit the hint when CanonicalName() is empty.

Nits

  • Test coverage: there is no automated test for the new branch or for the v1 change. The test plan is manual only. A unit test in internal/lock that stubs a non-404 Resolve error and checks it is not wrapped as ErrPackageNotFound would be cheap. A testscript case for devbox add <bare-nonexistent> would also work, if one can run without network.
  • Condition and comment: the fast-fail rests on "all top-level nixpkgs packages are indexed by search", checked on a sample of 150. That seems reasonable. It might be worth noting in the comment that it is a heuristic, in case search ever lags nixpkgs. A freshly added package, for example, would be rejected until the index catches up, where the nixpkgs fallback would have found it.
  • Error message: packageNotFoundError passes pkg.CanonicalName() to devbox search, which gives nodejs for nodejs@99999. That is the right behavior. For dotted names like foo.barbaz the hint is devbox search foo.barbaz, which is likely to return nothing, but it's harmless.

internal/lock/resolve.go

The errors.Is(err, searcher.ErrNotFound) change is correct and matches the v2 resolver and the check at line 107. Returning other errors unwrapped is better than reporting a network failure as "not found". This changes behavior for callers that relied on ErrPackageNotFound for any v1 failure. I grepped ErrNotFound usage and found nothing else that depends on the old behavior.

Verdict

Looks good once the non-devbox package case is handled.
· Branch: mikeland73/missing-package-error-msg

- Gate the not-found fast path on IsDevboxPackage so flake refs and
  other non-devbox packages keep propagating their original error
  instead of getting an empty `devbox search` hint.
- Note in the comment that the fast path is a heuristic.
- Add a unit test that /v1/resolve and /v2/resolve map only 404s to
  ErrPackageNotFound.
- Add a testscript for `devbox add` with a missing package.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.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

None yet

Development

Successfully merging this pull request may close these issues.

devbox add looks for nixpkgs in current path instead of elsewhere

1 participant