Skip to content

ExposureModeValidationService crashes daemon instead of logging gracefully + tailscale-funnel check too strict for sidecar deployments #862

@Aaronontheweb

Description

@Aaronontheweb

What happened

During netclaw setup (Step 10: Health Check), the daemon crashed with an unhandled exception from ExposureModeValidationService.StartAsync when tailscaled was not detected as a running process:

Mode='tailscale-funnel' requires 'tailscaled' to be running. Start 'tailscaled' or set ExposureMode to 'local' in netclaw.json.
   at Netclaw.Daemon.Services.ExposureModeValidationService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](...)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Program.<Main>$(String[] args)

This resulted in the health check failing with "Daemon did not become ready (personality setup skipped)" and a crash log written — but the error was presented as a raw stack dump rather than a graceful setup failure message.

Expected behavior

  1. Graceful error handling — The exception from ExposureModeValidationService should be caught by the setup/health check flow and presented as a clean, user-facing error message. The daemon should not emit a full stack trace during setup.

  2. Relaxed validation for sidecar/container deployments — The current check uses Process.GetProcessesByName("tailscaled") to verify the tunnel process is running locally. This is too strict for deployments where tailscale funnel runs in a sidecar container or on a different host. The check should either:

    • Attempt a connectivity test against the funnel endpoint instead of checking for a local process, OR
    • Provide a configuration option to skip the process check (e.g., ExposureModeValidationSkip or a tailscale-funnel mode that trusts the tunnel is externally managed)

Steps to reproduce

  1. Configure ExposureMode to tailscale-funnel in netclaw.json
  2. Ensure tailscaled is not running locally (e.g., running in a sidecar container or not installed)
  3. Run netclaw setup
  4. Observe the daemon crash with a raw stack trace at Step 10

Environment

  • Component: Netclaw.Daemon.Services.ExposureModeValidationService
  • File: src/Netclaw.Daemon/Services/ExposureModeValidationService.cs
  • Method: StartAsync — throws InvalidOperationException which is not caught by the hosting layer during setup

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions