go-delve/delve · warning

errBinaryInfoClose

errBinaryInfoClose

Error message

multiple errors closing executable files

What it means

errBinaryInfoClose is the sentinel Delve returns from BinaryInfo.Close when closing one or more internal image readers failed; the individual errors are aggregated and reported as 'multiple errors closing executable files'. It signals resource leaks (unclosed ELF/PE file handles) rather than corrupted debugging state.

Source

Thrown at pkg/proc/bininfo.go:1212

			return &md
		}
	}
	return nil
}

// typeToImage returns the image containing the give type.
func (bi *BinaryInfo) typeToImage(typ godwarf.Type) *Image {
	return bi.Images[typ.Common().Index]
}

func (bi *BinaryInfo) runtimeTypeTypename() string {
	if goversion.ProducerAfterOrEqual(bi.Producer(), 1, 21) {
		return "internal/abi.Type"
	}
	return "runtime._type"
}

var errBinaryInfoClose = errors.New("multiple errors closing executable files")

// Close closes all internal readers.
func (bi *BinaryInfo) Close() error {
	var errs []error
	for _, image := range bi.Images {
		if err := image.Close(); err != nil {
			errs = append(errs, err)
		}
	}
	switch len(errs) {
	case 0:
		return nil
	case 1:
		return errs[0]
	default:
		return errBinaryInfoClose
	}
}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Log the aggregated error but continue shutdown — it is usually non-fatal
  2. Avoid closing BinaryInfo more than once; tie Close to target-group teardown
  3. Check for binary replacement (rm/rename of the executable) while attached; re-attach after upgrade
  4. Inspect the wrapped individual errors to find which image failed to close

Example fix

// before
bi.Close() // error swallowed silently
// after
if err := bi.Close(); err != nil {
    if errors.Is(err, errBinaryInfoClose) {
        log.Printf("warning: leaked executable file handles: %v", err)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check: file handles for the images are still valid
for _, p := range imagePaths {
    if _, err := os.Stat(p); err != nil {
        log.Printf("executable file changed/unlinked: %s", p)
    }
}

Try / catch

if err := bi.Close(); err != nil {
    if errors.Is(err, errBinaryInfoClose) {
        log.Printf("non-fatal: %v", err) // log and continue teardown
    }
}

Prevention

When it happens

Trigger: Calling BinaryInfo.Close() (directly or via TargetGroup/detach cleanup) after the underlying image files were already closed, deleted, or failed to open in a partially-initialized state.

Common situations: Detaching from processes whose executable was deleted/upgraded on disk (common with atomic binary replacement); closing BinaryInfo twice; macOS code-signed binaries reopened between fork-exec steps failing re-open.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/815105669aea45c4. Report an issue: GitHub.