AlexxIT/go2rtc · error

exec: bin not in allow_paths:

Error message

exec: bin not in allow_paths: 

What it means

The exec stream source launches external binaries; for safety, if allow_paths is configured, only whitelisted executables may be started. This error means the binary that exec is about to spawn (cmd.Args[0]) is not in that whitelist, so the handler aborts and closes the command.

Solutions

  1. Add the exact executable path/name from the exec: URL to allow_paths
  2. Match formats: if the exec URL uses a bare name, allow the name; if absolute, allow the absolute path
  3. If the binary moved, update either the stream URL or the allowlist entry
  4. Remove allow_paths if per-binary restriction is not needed (not recommended)

Example fix

// before
allow_paths: ["/usr/bin/ffmpeg"]
streams:
  cam: exec:/usr/local/bin/ffmpeg ...
// after
allow_paths: ["/usr/bin/ffmpeg", "/usr/local/bin/ffmpeg"]
Defensive patterns

Strategy: validation

Validate before calling

if allowPaths != nil && !slices.Contains(allowPaths, bin) { return fmt.Errorf("add %q to allow_paths", bin) }

Try / catch

_, err := streams.Get(url); if err != nil && strings.Contains(err.Error(), "allow_paths") { /* resolve binary path and extend allowlist */ }

Prevention

When it happens

Trigger: A stream source exec:BIN ... where allow_paths is non-nil and does not exactly contain BIN (cmd.Args[0]). Includes cases where the URL's binary resolves differently (bare name vs absolute path) than the allowlist entry.

Common situations: After adding allow_paths to the config for the echo module, exec sources break because they use different binaries; binary path changed after a system update; typo in the exec URL; allowlist uses relative name while exec URL uses absolute path.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/0c33bd7b8a9aa56b. Report an issue: GitHub.

Appendix: source

Thrown at internal/exec/exec.go:92

	if i := strings.Index(rawURL, "{output}"); i > 0 {
		if rtsp.Port == "" {
			return nil, errors.New("exec: rtsp module disabled")
		}

		sum := md5.Sum([]byte(rawURL))
		path = "/" + hex.EncodeToString(sum[:])
		rawURL = rawURL[:i] + "rtsp://127.0.0.1:" + rtsp.Port + path + rawURL[i+8:]
	}

	cmd := shell.NewCommand(rawURL[5:]) // remove `exec:`
	cmd.Stderr = &logWriter{
		buf:   make([]byte, 512),
		debug: log.Debug().Enabled(),
	}

	if allowPaths != nil && !slices.Contains(allowPaths, cmd.Args[0]) {
		_ = cmd.Close()
		return nil, errors.New("exec: bin not in allow_paths: " + cmd.Args[0])
	}

	if s := query.Get("killsignal"); s != "" {
		sig := syscall.Signal(core.Atoi(s))
		cmd.Cancel = func() error {
			log.Debug().Msgf("[exec] kill with signal=%d", sig)
			return cmd.Process.Signal(sig)
		}
	}

	if s := query.Get("killtimeout"); s != "" {
		cmd.WaitDelay = time.Duration(core.Atoi(s)) * time.Second
	}

	if query.Get("backchannel") == "1" {
		return pcm.NewBackchannel(cmd, query.Get("audio"))
	}

View on GitHub (pinned to c245815e75)