hashicorp/nomad · error
failed to parse signal: %v
Error message
failed to parse signal: %v
What it means
The driver's SignalTask method parses the user-supplied signal string with `signals.Parse` before forwarding it to `ContainerKill`. If the string is not a recognized signal name (e.g. SIGTERM) or number, the driver returns this wrapped error and never sends anything to the container. It is a pure input-validation error, not a Docker API failure.
Source
Thrown at drivers/docker/driver.go:1903
return nil, drivers.ErrTaskNotFound
}
return h.Stats(ctx, interval, d.compute)
}
func (d *Driver) TaskEvents(ctx context.Context) (<-chan *drivers.TaskEvent, error) {
return d.eventer.TaskEvents(ctx)
}
func (d *Driver) SignalTask(taskID string, signal string) error {
h, ok := d.tasks.Get(taskID)
if !ok {
return drivers.ErrTaskNotFound
}
_, err := signals.Parse(signal)
if err != nil {
return fmt.Errorf("failed to parse signal: %v", err)
}
// TODO: review whether we can timeout in this and other Docker API
// calls without breaking the expected client behavior.
// see https://github.com/hashicorp/nomad/issues/9503
_, err = h.dockerClient.ContainerKill(d.ctx, h.containerID, mclient.ContainerKillOptions{Signal: signal})
return err
}
func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*drivers.ExecTaskResult, error) {
h, ok := d.tasks.Get(taskID)
if !ok {
return nil, drivers.ErrTaskNotFound
}
if len(cmd) == 0 {
return nil, fmt.Errorf("cmd is required, but was empty")
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Use a canonical signal name or number: "SIGTERM", "SIGINT", "SIGKILL", "SIGHUP", or integer like 9.
- Normalize input before calling (e.g. strings.ToUpper + ensure "SIG" prefix, or pass a number).
- Check the accepted signal list in hashicorp/nomad helper/signals for exact spellings.
- Catch the error at the caller and surface the valid-signal list to the user.
Example fix
// before driver.SignalTask(taskID, "term") // after driver.SignalTask(taskID, "SIGTERM")
Defensive patterns
Strategy: validation
Validate before calling
var validSignals = map[string]bool{"SIGTERM": true, "SIGINT": true, "SIGKILL": true, "SIGHUP": true, "SIGQUIT": true, "SIGUSR1": true, "SIGUSR2": true}
func isValidSignal(s string) bool {
if n, err := strconv.Atoi(s); err == nil { return n > 0 && n < 65 }
return validSignals[strings.ToUpper(s)]
}
if !isValidSignal(signal) { return fmt.Errorf("invalid signal %q", signal) } Prevention
- Always use canonical uppercase "SIGXXX" names or numeric signal values.
- Keep a whitelist of supported signals in your tooling.
- Normalize user input (uppercase, ensure SIG prefix) before passing to the driver.
When it happens
Trigger: Calling driver.SignalTask(taskID, signal) where `signal` is an unknown name like "sigterm" (wrong case), "TERM15", "SIG_KILL", an empty string, or an out-of-range number.
Common situations: Task config `kill_signal` misspelled; API/UI clients sending lowercase "term" or "sigusr1" variants not in the accepted set; plugins forwarding raw user input.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- does not match registry specification
- Failed to parse signal %q
- invalid cgroup permission string: %q
- invalid source, must be "" for tmpfs
- invalid mount type, must be "bind", "volume", "tmpfs": %q
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f079fb984c69a453.
Report an issue: GitHub.