From b1056861f1274d362c5c0e6a0bfb1f1c9ce82b19 Mon Sep 17 00:00:00 2001 From: mitchell Date: Tue, 14 Jul 2026 11:11:55 -0400 Subject: [PATCH] ENG-1979: Fail cleanly when the state publish --build directory is missing Running `state publish --build` against a non-existent source directory crashed with a nil-pointer panic instead of reporting the bad path. Two fixes: - Validate the --build directory exists up front and return an InputError naming the offending path, before any metadata resolution, key fetch, or wheel build. - Fix buildWrappedArtifact's error path: the deferred cleanup called the named `cleanup` return, which the `return "", nil, err` statements had already set to nil, so it called a nil function value and panicked. The deferred cleanup now uses a local closure, so an in-build failure returns its real error instead of crashing. Co-Authored-By: Claude Opus 4.8 (1M context) --- internal/runners/publish/build.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/runners/publish/build.go b/internal/runners/publish/build.go index 4c2881534c..93dae93168 100644 --- a/internal/runners/publish/build.go +++ b/internal/runners/publish/build.go @@ -28,6 +28,9 @@ func (r *Runner) generateEncryptedArtifact(params *Params) (cleanup func(), rerr if r.project == nil { return nil, locale.NewInputError("err_publish_build_no_project", "The '[ACTIONABLE]--build[/RESET]' flag requires a project so the organization can be determined.") } + if !fileutils.DirExists(params.Build) { + return nil, locale.NewInputError("err_publish_build_dir_not_found", "The '[ACTIONABLE]--build[/RESET]' source directory does not exist: [ACTIONABLE]{{.V0}}[/RESET]", params.Build) + } meta, err := wheel.ResolveMetadata(params.Build, wheel.Metadata{Name: params.Name, Version: params.Version}) if err != nil { @@ -95,12 +98,13 @@ func buildWrappedArtifact(srcDir string, meta wheel.Metadata, key []byte, keyID if err != nil { return "", nil, errs.Wrap(err, "Could not create temp dir") } - cleanup = func() { _ = os.RemoveAll(tmpDir) } + removeTmpDir := func() { _ = os.RemoveAll(tmpDir) } defer func() { if rerr != nil { - cleanup() + removeTmpDir() } }() + cleanup = removeTmpDir wheelPath, err := wheel.Pack(srcDir, meta, tmpDir) if err != nil {