hashicorp/nomad · error

unsupported signal type: %q

Error message

unsupported signal type: %q

What it means

grpcExecutorClient.Signal only accepts os.Signal values that are syscall.Signal (integer-numbered Unix/Windows signals). This error means the caller passed a signal implementation that cannot be represented as a syscall.Signal, so it cannot be serialized into the gRPC SignalRequest.

Source

Thrown at drivers/shared/executor/grpc_client.go:172

		stats, err := drivers.TaskStatsFromProto(resp.Stats)
		if err != nil {
			c.logger.Error("failed to decode stats from RPC", "error", err, "stats", resp.Stats)
			continue
		}

		select {
		case ch <- stats:
		case <-ctx.Done():
			return
		}
	}
}

func (c *grpcExecutorClient) Signal(s os.Signal) error {
	ctx := context.Background()
	sig, ok := s.(syscall.Signal)
	if !ok {
		return fmt.Errorf("unsupported signal type: %q", s.String())
	}
	req := &proto.SignalRequest{
		Signal: int32(sig),
	}
	if _, err := c.client.Signal(ctx, req); err != nil {
		return err
	}

	return nil
}

func (c *grpcExecutorClient) Exec(deadline time.Time, cmd string, args []string) ([]byte, int, error) {
	ctx := context.Background()
	pbDeadline, err := ptypes.TimestampProto(deadline)
	if err != nil {
		return nil, 0, err
	}
	req := &proto.ExecRequest{

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Convert to a syscall.Signal before calling: executor.Signal(syscall.SIGTERM) instead of passing a custom os.Signal
  2. Map named signals from task config (e.g. "SIGINT") to syscall.Signal values via syscall.Signals parsing
  3. Reject or translate unsupported signals at the driver layer before invoking Signal
  4. Check the value at runtime with a type assertion and handle unsupported signals explicitly

Example fix

// before
var sig os.Signal = myCustomSignal{}
executor.Signal(sig)
// after
if s, ok := mySignal.(syscall.Signal); ok {
    executor.Signal(s)
} else {
    executor.Signal(syscall.SIGTERM)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := sig.(syscall.Signal); !ok { sig = syscall.SIGTERM }

Type guard

func isSyscallSignal(s os.Signal) (syscall.Signal, bool) {
    sig, ok := s.(syscall.Signal)
    return sig, ok
}

Try / catch

if err := executor.Signal(sig); err != nil && strings.Contains(err.Error(), "unsupported signal type") {
    err = executor.Signal(syscall.SIGTERM)
}

Prevention

When it happens

Trigger: Calling executor.Signal() with a custom signal type, or with values like os.Interrupt wrapped in a non-syscall.Signal implementation of os.Signal.

Common situations: Driver/plugin authors forwarding user-specified signals from task config; using os.Interrupt/os.Kill constants in code paths expecting syscall.SIGTERM-style values; Go code compiling where os.Signal is satisfied by non-numeric signal types.

Related errors


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