fatedier/frp · error

failed to execute command %v: %v

Error message

failed to execute command %v: %v

What it means

ExecSource.Resolve() wraps the exec.Cmd.Output() failure for the configured command. The wrapped error is usually an *exec.ExitError (non-zero exit or signal kill), a "command not found" path error, or a context-deadline error if ctx was cancelled. Only stdout is captured; anything the command writes to stderr is discarded by Output().

Source

Thrown at pkg/config/v1/value_source.go:153

}

// Resolve reads and returns the content captured from stdout of launched subprocess.
func (e *ExecSource) Resolve(ctx context.Context) (string, error) {
	if err := e.Validate(); err != nil {
		return "", err
	}

	cmd := exec.CommandContext(ctx, e.Command, e.Args...)
	if len(e.Env) != 0 {
		cmd.Env = os.Environ()
		for _, env := range e.Env {
			cmd.Env = append(cmd.Env, env.Name+"="+env.Value)
		}
	}

	content, err := cmd.Output()
	if err != nil {
		return "", fmt.Errorf("failed to execute command %v: %v", e.Command, err)
	}

	// Trim whitespace, which is important for exec-based tokens
	return strings.TrimSpace(string(content)), nil
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Run the exact command manually as the frp service user to see the real failure: sudo -u frp <command> <args...>.
  2. Ensure the binary/script exists in the container/image and PATH; use an absolute path for command.
  3. If the command is slow, pass a context with a longer deadline to Resolve().
  4. Check exit status in the returned error (*exec.ExitError) — stderr output is not included in this error message.
  5. For scripts, verify the executable bit and shebang.

Example fix

# before
[auth.token.valueSource]
type = "exec"
exec.command = "get-token"   # not in PATH inside container

# after
exec.command = "/usr/local/bin/get-token"
# or inline shell:
exec.command = "sh"
exec.args = ["-c", "cat /run/secrets/token"]
Defensive patterns

Strategy: try-catch

Validate before calling

func execResolves(command string, args []string) error {
	if command == "" {
		return errors.New("empty command")
	}
	path, err := exec.LookPath(command)
	if err != nil {
		return fmt.Errorf("command %q not found in PATH: %w", command, err)
	}
	_ = path
	return nil
}

Try / catch

val, err := vs.Resolve(ctx)
if err != nil {
	var exitErr *exec.ExitError
	if errors.As(err, &exitErr) {
		// command ran but failed: capture stderr yourself by running it out-of-band; fix credentials/env
		log.Printf("helper exited %d", exitErr.ExitCode())
	} else if ctx.Err() != nil {
		// deadline: lengthen the context timeout
	}
	return err
}

Prevention

When it happens

Trigger: ValueSource{Type: "exec"}.Resolve(ctx) where the command exits non-zero, does not exist in PATH, is not executable, is killed by the context deadline, or cannot run due to missing runtime (e.g. no shell, missing interpreter).

Common situations: Token-fetch helper (aws sts get-session-token, vault print token) fails because of expired credentials or no network; command installed on the admin's laptop but not in the frpc container image; context deadline too short for a cloud API call; script not marked executable or uses a shebang for a missing interpreter.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/7bb2403ef96ca7fc. Report an issue: GitHub.