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

  1. Use a canonical signal name or number: "SIGTERM", "SIGINT", "SIGKILL", "SIGHUP", or integer like 9.
  2. Normalize input before calling (e.g. strings.ToUpper + ensure "SIG" prefix, or pass a number).
  3. Check the accepted signal list in hashicorp/nomad helper/signals for exact spellings.
  4. 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

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

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/f079fb984c69a453. Report an issue: GitHub.