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
- Verify the tinytun binary exists and is executable (check GetTinyTunBinPath output and run it manually).
- Confirm /usr/lib/tinytun/tinytun-ebpf.o exists or set TINYTUN_EBPF_OBJECT to the correct path.
- Read the wrapped %w cause: ENOENT -> install binary, EACCES -> chmod/permissions, ENOEXEC -> wrong arch binary.
- Run as root with eBPF/capabilities available (CAP_BPF/CAP_NET_ADMIN) since tinytun needs them.
- 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
- Check IsTinyTunEnabled() and binary/eBPF-object existence before enabling tinytun mode.
- Run with root/eBPF capabilities.
- Verify binary architecture matches the host.
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
- networksetup get: %v
- failed to hijackDNS: [write] %v
- dns port 53 is occupied
- dns port 53 is occupied by %v(%v)
- error when executing the transparent pre start hook: %w
AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05).
Data as JSON: /api/errors/b275e145d774c289.
Report an issue: GitHub.