v2rayA/v2rayA · error

failed to start tinytun: %w

Error message

failed to start tinytun: %w

What it means

This error wraps the underlying error returned by exec.Cmd.Start() when the tinytun process (an eBPF-based TUN transparent-proxy helper) fails to launch. The library throws it because the external tinytun binary could not be spawned at all (binary missing, not executable, missing eBPF object file, or OS-level exec failure). The wrapped cause (%w) is in the message and must be inspected to know the real reason.

Source

Thrown at service/kernel/v2ray/tinytun_enabled.go:839

	setting := configure.GetSettingNotNil()

	cmdArgs := []string{"run", "--config", configPath}
	cmd := exec.CommandContext(ctx, binPath, cmdArgs...)
	cmd.Stdout = tinytunLineWriter{}
	cmd.Stderr = tinytunLineWriter{}

	// On Linux, when the user selects the eBPF process-exclusion backend,
	// set TINYTUN_EBPF_OBJECT so TinyTun loads the eBPF programs from the
	// standard installation path (/usr/lib/tinytun/tinytun-ebpf.o).
	if runtime.GOOS == "linux" && setting.TunProcessBackend == "ebpf" {
		if os.Getenv("TINYTUN_EBPF_OBJECT") == "" {
			cmd.Env = append(os.Environ(), "TINYTUN_EBPF_OBJECT=/usr/lib/tinytun/tinytun-ebpf.o")
		}
	}

	if err = cmd.Start(); err != nil {
		cancel()
		return fmt.Errorf("failed to start tinytun: %w", err)
	}

	doneCh := make(chan struct{})

	tinyTunState.mu.Lock()
	if tinyTunState.cancel != nil {
		tinyTunState.cancel()
	}
	// Set the new cancel function before resetting the stopping flag so that
	// any concurrent stopTinyTun that reads stopping==0 already sees the new
	// cancel and will correctly cancel the new process.
	tinyTunState.cancel = cancel
	tinyTunState.done = doneCh
	atomic.StoreInt32(&tinyTunState.stopping, 0)
	tinyTunState.mu.Unlock()

	// Monitor for unexpected exits: if TinyTun dies without its context being cancelled,
	// the proxy is in an inconsistent state and must be stopped.

View on GitHub (pinned to 71e5442fc5)

Solutions

  1. Verify the tinytun binary exists and is executable (check GetTinyTunBinPath output and run it manually).
  2. Confirm /usr/lib/tinytun/tinytun-ebpf.o exists or set TINYTUN_EBPF_OBJECT to the correct path.
  3. Read the wrapped %w cause: ENOENT -> install binary, EACCES -> chmod/permissions, ENOEXEC -> wrong arch binary.
  4. Run as root with eBPF/capabilities available (CAP_BPF/CAP_NET_ADMIN) since tinytun needs them.
  5. Rebuild v2rayA with -tags tinytun matching your platform.

Example fix

// before
cmd.Env = append(os.Environ(), "TINYTUN_EBPF_OBJECT=/usr/lib/tinytun/tinytun-ebpf.o")
if err = cmd.Start(); err != nil { ... }
// after
if _, err := os.Stat(tinytunBin); err != nil {
	return fmt.Errorf("tinytun binary missing: %w", err)
}
if _, err := os.Stat(ebpfObjectPath); err != nil {
	return fmt.Errorf("eBPF object missing: %w", err)
}
cmd.Env = append(os.Environ(), "TINYTUN_EBPF_OBJECT="+ebpfObjectPath)
Defensive patterns

Strategy: try-catch

Validate before calling

if !v2ray.IsTinyTunEnabled() { return errors.New("tinytun not compiled in") }
if _, err := os.Stat("/usr/lib/tinytun/tinytun-ebpf.o"); err != nil { return err }

Try / catch

if err := setupTransparentProxy(); err != nil {
	if strings.Contains(err.Error(), "failed to start tinytun") {
		log.Warnf("tinytun start failed: %v — falling back to redirect mode", err)
	}
}

Prevention

When it happens

Trigger: startTinyTun builds an exec.Command for the tinytun binary (with env TINYTUN_EBPF_OBJECT=/usr/lib/tinytun/tinytun-ebpf.o when configured) and calls cmd.Start(); any non-nil error from Start (binary not found, exec format error, permission denied, missing TINYTUN_EBPF_OBJECT file check done before spawn) triggers this wrapper, after calling cancel() to unwind the context.

Common situations: Building with -tags tinytun on a system where the tinytun binary or /usr/lib/tinytun/tinytun-ebpf.o is absent; wrong architecture binary (exec format error); non-root user lacking permission to run eBPF tooling; PATH misconfigured in systemd service environments.

Related errors


AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05). Data as JSON: /api/errors/b275e145d774c289. Report an issue: GitHub.