go-task/task · error

task: Command "%s" failed: %s

Error message

task: Command "%s" failed: %s

What it means

Task wraps any failure from running a shell command during dynamic variable evaluation (the `sh:` / `cmd:` variable sources) with this message, embedding the command string and the underlying exec error. It indicates that a command used to compute a task variable exited non-zero or could not be executed at all. The raw OS error is preserved via %s so the root cause (exit status, missing binary, permission) is visible in the wrapped text.

Source

Thrown at compiler.go:179

	if result, ok := c.dynamicCache[*v.Sh]; ok {
		return result, nil
	}

	// NOTE(@andreynering): If a var have a specific dir, use this instead
	if v.Dir != "" {
		dir = v.Dir
	}

	var stdout bytes.Buffer
	opts := &execext.RunCommandOptions{
		Command: *v.Sh,
		Dir:     dir,
		Stdout:  &stdout,
		Stderr:  c.Logger.Stderr,
		Env:     e,
	}
	if err := execext.RunCommand(context.Background(), opts); err != nil {
		return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
	}

	// Trim a single trailing newline from the result to make most command
	// output easier to use in shell commands.
	result := strings.TrimSuffix(stdout.String(), "\r\n")
	result = strings.TrimSuffix(result, "\n")

	c.dynamicCache[*v.Sh] = result
	// Never print the resolved value of a secret variable, even in verbose mode
	logResult := result
	if v.Secret {
		logResult = "*****"
	}
	c.Logger.VerboseErrf(logger.Magenta, "task: dynamic variable: %q result: %q\n", *v.Sh, logResult)

	return result, nil
}

View on GitHub (pinned to 385e5ad92a)

Solutions

  1. Run the failing command manually in the task's directory to see the real error and fix the command or its inputs
  2. Guard the command so it exits 0 when information is unavailable, e.g. `sh: git describe --tags || echo unknown`
  3. Install the missing tool or fix PATH/Env so the command can be found
  4. If the exit code is expected, capture it in the shell (e.g. `sh: cat file 2>/dev/null || true`)

Example fix

# before
vars:
  VERSION:
    sh: git describe --tags
# after
vars:
  VERSION:
    sh: git describe --tags || echo v0.0.0
Defensive patterns

Strategy: try-catch

Validate before calling

// check tools used by sh: variables exist before running
cmds := ["git", "make"]
for _, c := range cmds {
  if _, err := exec.LookPath(c); err != nil {
    return fmt.Errorf("missing tool for task vars: %s", c)
  }
}

Try / catch

err := task.Run(ctx, t)
if err != nil && strings.Contains(err.Error(), `Command "`) && strings.Contains(err.Error(), "failed") {
  // extract cmd + cause, decide: retry with fallback var or surface to user
}

Prevention

When it happens

Trigger: A task's variable uses `sh:` (or `cmd:` on Windows) and the Compiler's dynamic variable handler executes it via execext.RunCommand; the command exits non-zero or fails to start. Raised in HandleDynamicVar while compiling task variables before the task runs.

Common situations: Referencing a nonexistent binary (e.g. `git` not installed), running a script that fails in CI but not locally, wrong working directory (Dir), missing environment variables expected by the command, or commands that print to stderr and return non-zero by design.

Related errors


AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05). Data as JSON: /api/errors/18cf768958963798. Report an issue: GitHub.