go-make-run-no-dotenv
The project was reconstructed in /workspace (no repo was checked out) to reproduce and fix the bug. The root cause: config.Load() read only the process environment, so a local .env was never consulted and make run panicked with required environment variable DATABASE_URL is not set.
Fix 1 — add github.com/joho/godotenv v1.5.1:
go get github.com/joho/godotenv@v1.5.1
Fix 2 — load .env at the top of config.Load(), ignoring the error when .env is absent. godotenv.Load() (not Overload()) never overrides variables already set in the process environment, so container env_file injection keeps working:
package config
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DatabaseURL string
AppKey []byte
}
// Load reads configuration from the environment, falling back to a local
// .env file when present, and panics if a required variable is still
// missing. godotenv.Load() never overrides variables already set in the
// process environment, so container env_file values always win; its error
// is ignored because a .env file is optional.
func Load() *Config {
_ = godotenv.Load()
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
panic("required environment variable DATABASE_URL is not set")
}
key := os.Getenv("APP_KEY")
if len(key) != 32 {
panic(fmt.Sprintf("required environment variable APP_KEY must be exactly 32 bytes, got %d", len(key)))
}
return &Config{DatabaseURL: dbURL, AppKey: []byte(key)}
}
Fix 3 — .env.example placeholder was 24 bytes (0123456789abcdef01234567) and tripped the 32-byte key validation once copied to .env; corrected to exactly 32 bytes:
APP_KEY=0123456789abcdef0123456789abcdef
Tests (internal/config/config_test.go), including the two required ones:
// TestLoad_EnvOverridesDotenv — .env has other values, process env wins (no-override).
func TestLoad_EnvOverridesDotenv(t *testing.T) {
t.Setenv("DATABASE_URL", "postgres://env:secret@db:5432/env?sslmode=disable")
t.Setenv("APP_KEY", envAppKey) // 32 bytes
dir := t.TempDir()
os.WriteFile(filepath.Join(dir, ".env"),
[]byte("DATABASE_URL=postgres://dotenv:secret@db:5432/dotenv?sslmode=disable\n"+
"APP_KEY=0123456789abcdef0123456789abcdef\n"), 0o600)
t.Chdir(dir)
cfg := Load()
// assert cfg.DatabaseURL == env value, cfg.AppKey == env value
}
// TestLoad_NoDotenvFile — empty dir, env vars set: Load succeeds.
func TestLoad_NoDotenvFile(t *testing.T) {
t.Chdir(t.TempDir())
t.Setenv("DATABASE_URL", "postgres://env:secret@db:5432/env?sslmode=disable")
t.Setenv("APP_KEY", envAppKey)
cfg := Load() // no panic, correct values
}
Plus edge-case tests: missing DATABASE_URL with no .env still panics (guard rail), and the 24-byte key is rejected while the 32-byte key is accepted.
Reproduced the bug first — with a valid `.env` present, `go run ./cmd/asce-api` panicked exactly as reported: ``` panic: required environment variable DATABASE_URL is not set ``` After the fix, verified end-to-end: | Scenario | Result | |---|---| | `make run` with `.env` (32-byte key) | `connecting to database postgres://user:pass@localhost:5432/asce?sslmode=disable`, exit 0 | | `DATABASE_URL` exported + conflicting `.env` | env value wins — `postgres://container:...` (no-override semantics for container `env_file`) | | No `.env`, no env vars | still panics `required environment variable DATABASE_URL is not set` (correct guard, exit 2) | | 24-byte placeholder in `.env` | rejected: `APP_KEY must be exactly 32 bytes, got 24` | | 32-byte placeholder in `.env` | accepted | Tests: `go test ./... -v` — 4 top-level test functions, all PASS (including subtests: 5 cases): ``` === RUN TestLoad_EnvOverridesDotenv --- PASS === RUN TestLoad_NoDotenvFile --- PASS === RUN TestLoad_EnvFileMissingRequiredStillPanics --- PASS === RUN TestLoad_AppKeyLengthValidation --- PASS (2/2 subtests) ok asce-api/internal/config ``` `go vet ./...` clean; `go mod tidy` resolved `github.com/joho/godotenv v1.5.1` into `go.mod`/`go.sum`.
{"model": "deepseek-v4-flash", "problem_class": "go-make-run-no-dotenv", "result": "passed", "tests": 4}