gastownhall/beads · error

%w: %s

Error message

%w: %s

What it means

The credential helper runner executes an external credential command and, when it exits non-zero, wraps the exec error with the helper's captured stderr. This gives the developer both the OS-level failure and the helper's own diagnostic message in one error chain.

Source

Thrown at internal/creds/command.go:97

	credCache   = map[string]cachedCred{}

	// credRunner runs the helper; a package var so tests can stub it without a shell.
	credRunner = func(ctx context.Context, command string) ([]byte, error) {
		// POSIX shells parse the helper command; native Windows has no `sh`, so
		// dispatch through cmd.exe there so a bare Windows bd does not hard-fail
		// every *_PASSWORD_COMMAND / CREDENTIAL_COMMAND in the fail-closed ladder.
		var cmd *exec.Cmd
		if runtime.GOOS == "windows" {
			cmd = exec.CommandContext(ctx, "cmd.exe", "/C", command)
		} else {
			cmd = exec.CommandContext(ctx, "sh", "-c", command)
		}
		var stdout, stderr bytes.Buffer
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr
		if err := cmd.Run(); err != nil {
			if msg := strings.TrimSpace(stderr.String()); msg != "" {
				return nil, fmt.Errorf("%w: %s", err, msg)
			}
			return nil, err
		}
		return stdout.Bytes(), nil
	}
)

// resolveCredentialToken returns the token (and any username/expiry) for the given
// helper command, using a process-level cache keyed by the command so repeated opens
// don't re-spawn the helper until the token is near expiry. It is concurrency-safe.
func resolveCredentialToken(ctx context.Context, command string) (token, username string, expiry time.Time, err error) {
	now := time.Now()

	credCacheMu.Lock()
	if c, ok := credCache[command]; ok && now.Before(c.expires.Add(-credExpirySkew)) {
		tok, user, exp := c.token, c.username, c.expires
		credCacheMu.Unlock()
		return tok, user, exp, nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the trailing text after the colon — it is the helper's stderr and usually states the real cause (e.g. 'gh auth: not logged in').
  2. Re-authenticate with the helper (e.g. `gh auth login`, `docker login`).
  3. Run the credential command manually with the same arguments to reproduce and debug its stderr.
  4. Verify the helper binary version on PATH is current.

Example fix

// before
// error: exit status 1: gh auth token: not logged in
// after
$ gh auth login   # then retry the credential resolution
Defensive patterns

Strategy: try-catch

Validate before calling

cmd := exec.Command(helper, args...)
if _, err := exec.LookPath(helper); err != nil {
    // helper missing; fix config before relying on it
}

Try / catch

cred, err := creds.Resolve(ctx)
if err != nil {
    var ee *exec.ExitError
    if errors.As(err, &ee) {
        // stderr text after the colon is the helper's own message
    }
    return fmt.Errorf("credential resolution failed: %w", err)
}

Prevention

When it happens

Trigger: The configured credential command (e.g. a gh/docker credential helper script) exits non-zero after printing a message to stderr; cmd.Run returns an *exec.ExitError and stderr is non-empty.

Common situations: Credential helper not authenticated (expired OAuth token), helper script crashing with its own error message, helper refusing to serve credentials for the requested host, PATH pointing at an old/broken helper binary.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/dc8747d2c32613ab. Report an issue: GitHub.