Skip to content

fix(env): warn instead of failing when env_from file is missing - #2901

Merged
mikeland73 merged 1 commit into
mainfrom
claude/focused-goldberg-tqbvgg
Sep 15, 2026
Merged

mikeland73 merged 1 commit into
mainfrom
claude/focused-goldberg-tqbvgg

Conversation

@mikeland73

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2504.

When env_from points to a .env file that does not exist yet, Devbox exited early with:

Error: failed parsing .private.env file. Error: failed to open file: /path/.private.env

This is a papercut on first-time setup: the referenced file is typically untracked and intended to be created by a command in init_hook (e.g. cp -n .env.example .env). Because parsing env_from happens before init_hook runs, the environment could never be enabled to bootstrap the file in the first place.

Fix

  • internal/devconfig/configfile/env.go: ParseEnvsFromDotEnv now wraps the underlying os.Open error with %w, so callers can distinguish a missing file (errors.Is(err, os.ErrNotExist)) from a genuine parse error.
  • internal/devbox/devbox.go: configEnvs treats a missing env_from file as a warning and continues enabling the environment, instead of returning a hard error. Real parse errors (file exists but is malformed) still fail as before.

New behavior when the file is missing:

Warning: Ignoring env_from directive: file ".private.env" does not exist.

Changes

  • internal/devconfig/configfile/env.go: wrap the open error so missing files are detectable.
  • internal/devbox/devbox.go: warn-and-continue on a missing env_from file.
  • internal/devconfig/configfile/env_test.go: new TestParseEnvsFromDotEnv covering a valid .env file and the missing-file (os.ErrNotExist) regression.

How was it tested?

  • go test ./internal/devconfig/configfile/ -run TestParseEnvsFromDotEnv -v — passes.
  • go build ./internal/... and go vet ./internal/devconfig/configfile/ ./internal/devbox/ — clean.

Community Contribution License

All community contributions in this pull request are licensed to the project
maintainers under the terms of the
Apache 2 License.

By creating this pull request, I represent that I have the right to license the
contributions to the project maintainers under the Apache 2 License as stated in
the
Community Contribution License.


cc @t-monaghan (issue reporter) — thanks for the clear write-up and reproduction.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UiVJfTdwpkKJ4UDn9opMMX


Generated by Claude Code

A missing file referenced by `env_from` caused Devbox to exit early with
"failed parsing <file> file. Error: failed to open file: ...", preventing
the environment from being enabled. The referenced file is often untracked
and intended to be created by a command in `init_hook` (e.g.
`cp -n .env.example .env`), so failing before the hook runs is a papercut.

ParseEnvsFromDotEnv now wraps the underlying open error so callers can
detect a missing file via errors.Is(err, os.ErrNotExist). configEnvs uses
this to warn and continue when the env_from file does not exist, while
still returning a hard error for genuine parse failures.

Fixes #2504

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UiVJfTdwpkKJ4UDn9opMMX
Copilot AI review requested due to automatic review settings July 3, 2026 14:11

Copilot AI 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.

Pull request overview

This PR fixes a first-time setup papercut where env_from points to an untracked .env file that may not exist yet (often created later by init_hook). Instead of failing early, Devbox now warns and continues enabling the environment when the referenced .env file is missing, while still failing on real parse errors.

Changes:

  • Wrap os.Open errors in ParseEnvsFromDotEnv so callers can detect missing-file cases via errors.Is(err, os.ErrNotExist).
  • Update Devbox.configEnvs to warn-and-continue when the env_from file is missing, preserving hard failures for genuine parse errors.
  • Add unit tests covering successful parsing and the missing-file regression case.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
internal/devconfig/configfile/env.go Wraps .env open errors with %w so missing files can be detected reliably.
internal/devconfig/configfile/env_test.go Adds coverage for parsing an existing .env and for ensuring missing files return an os.ErrNotExist-detectable error.
internal/devbox/devbox.go Converts missing env_from .env files into a warning instead of a fatal error during environment enablement.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mikeland73

Copy link
Copy Markdown
Collaborator Author

@claude please review this PR for correctness, and flag anything that would block merging.

@claude

claude Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Claude finished @mikeland73's task in 2m 30s —— View job


Reviewing PR #2901

  • Gather context (diff, related code)
  • Review env.go changes
  • Review devbox.go changes
  • Review new tests
  • Post review feedback

Review

I reviewed the diff (git diff be5b810..b60866d, the PR's single commit) and the surrounding code. Overall this is a small, well-scoped fix and I didn't find anything that should block merging.

Correctness

  • internal/devconfig/configfile/env.go:34-40 — os.Open returns an *fs.PathError wrapping os.ErrNotExist for a missing file; wrapping it with %w is correct and lets callers use errors.Is(err, os.ErrNotExist).
  • internal/devbox/devbox.go:1029-1053 — configEnvs correctly special-cases os.ErrNotExist to warn-and-continue while still hard-failing on genuine parse errors (e.g. permission denied, malformed file). Note devbox.go imports errors as github.com/pkg/errors, not the stdlib package — I verified pkg/errors v0.9.1 (the version pinned in go.mod) re-exports Is/As/Unwrap as thin wrappers around the stdlib implementations, and this exact pattern (errors.Is(err, os.ErrNotExist)) is already used elsewhere in this same file (e.g. lines 86, 97, 102, 105), so this works as intended and is consistent with existing conventions.
  • When err is os.ErrNotExist, parsedEnvs is nil; the subsequent for k, v := range parsedEnvs is a safe no-op on a nil map, so environment setup proceeds cleanly with nothing added from the missing file.
  • The new tests in env_test.go correctly exercise both the happy path and the errors.Is(err, os.ErrNotExist) regression case, and use the exported ConfigFile.EnvFrom/AbsRootPath fields correctly.

Minor, non-blocking observations

  1. No test coverage for the actual UX change (devbox.go's warn-and-continue behavior in configEnvs). The new test only covers ParseEnvsFromDotEnv's error wrapping, not that configEnvs warns and continues rather than failing. Worth considering for a follow-up, but not a blocker given the logic is simple and directly mirrors an existing pattern in the same function (the envsec branch above it).
  2. Slightly redundant error text for the genuine-parse-error path: fmt.Errorf("failed to open file: %s: %w", envFileAbsPath, err) will include the path twice when err is a *fs.PathError (which already stringifies as open <path>: <reason>), e.g. failed to open file: /x/.env: open /x/.env: permission denied. Cosmetic only.
  3. I was unable to run go build/go test myself in this sandboxed environment (tool restrictions on go/git fetch commands), so I relied on manual code tracing rather than executing the test suite. The PR description states go test ./internal/devconfig/configfile/ -run TestParseEnvsFromDotEnv -v, go build ./internal/..., and go vet all pass, which is consistent with what I'd expect from the code.

Verdict

No correctness issues found that would block merging. The two notes above are optional polish, not blockers.

@mikeland73 mikeland73 added the ready for human review Automated review passed; needs a maintainer to review and merge label Sep 14, 2026
@mikeland73
mikeland73 merged commit a9f0cad into main Sep 15, 2026
27 checks passed
@mikeland73
mikeland73 deleted the claude/focused-goldberg-tqbvgg branch September 15, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for human review Automated review passed; needs a maintainer to review and merge

Development

Successfully merging this pull request may close these issues.

file referenced by env_from not existing should not stop devbox enabling the environment

3 participants