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
- Run the failing command manually in the task's directory to see the real error and fix the command or its inputs
- Guard the command so it exits 0 when information is unavailable, e.g. `sh: git describe --tags || echo unknown`
- Install the missing tool or fix PATH/Env so the command can be found
- 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
- Make every sh: variable command exit 0 with a sensible fallback (|| echo default)
- Pin and document tool dependencies (git, jq, etc.) in your environment
- Test Taskfiles in CI so failing variable commands surface early
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
- task: failed to get variables: %w
- task: precondition not met
- matrix reference %q must resolve to a list
AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05).
Data as JSON: /api/errors/18cf768958963798.
Report an issue: GitHub.