gastownhall/beads · error

procid: unsupported signal

Error message

procid: unsupported signal %v

What it means

Handle.Signal only supports signals representable as syscall.Signal (real Unix signals). If the caller passes an os.Signal implementation that is not a syscall.Signal, the library cannot convert it for syscall.Kill and returns this error without signaling anything.

Solutions

  1. Pass values of type syscall.Signal, e.g. syscall.SIGTERM, syscall.SIGKILL.
  2. Convert your abstraction to syscall.Signal before calling: syscall.Signal(int(mySig)).
  3. Check your signal constants are not redefined in a custom package; import syscall and use its constants.

Example fix

// before
var mySignal os.Signal = myPkg.Signal("terminate")
h.Signal(mySignal) // unsupported signal
// after
import "syscall"
h.Signal(syscall.SIGTERM)
Defensive patterns

Strategy: validation

Validate before calling

sig, ok := mySignal.(syscall.Signal)
if !ok {
    return fmt.Errorf("only syscall.Signal values are supported, got %T", mySignal)
}

Type guard

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

Try / catch

if err := h.Signal(sig); err != nil {
    if strings.Contains(err.Error(), "unsupported signal") {
        return fmt.Errorf("convert %T to syscall.Signal before calling Signal", sig)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Handle.Signal with a custom type implementing os.Signal (e.g. a wrapper or a non-Unix signal constant) instead of syscall.SIGKILL/syscall.SIGTERM or another syscall.Signal value.

Common situations: Passing signals from an abstraction layer over os/exec or a cross-platform signal enum; passing nil or a mock signal in tests; passing a Windows-style signal value on darwin builds.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/aab9e5e457825102. Report an issue: GitHub.

Appendix: source

Thrown at internal/procid/procid_darwin.go:65

		return nil, err
	}
	if !match {
		return nil, fmt.Errorf("procid: process %d does not match token", pid)
	}
	return &Handle{pid: pid, token: tok}, nil
}

func (h *Handle) Signal(sig os.Signal) error {
	match, err := Verify(h.pid, h.token)
	if err != nil {
		return err
	}
	if !match {
		return fmt.Errorf("procid: process %d no longer matches token", h.pid)
	}
	unixSig, ok := sig.(syscall.Signal)
	if !ok {
		return fmt.Errorf("procid: unsupported signal %v", sig)
	}
	if err := syscall.Kill(h.pid, unixSig); err != nil {
		if isFatalSignal(unixSig) && errors.Is(err, unix.ESRCH) {
			return nil
		}
		return fmt.Errorf("procid: signal %d: %w", h.pid, err)
	}
	if isFatalSignal(unixSig) {
		return h.confirmFatalSignal()
	}
	match, err = Verify(h.pid, h.token)
	if err != nil {
		return err
	}
	if !match {
		return fmt.Errorf("procid: process %d no longer matches token", h.pid)
	}
	return nil

View on GitHub (pinned to 71377f2769)