benbjohnson/litestream · critical

cannot run windows service as unix process

Error message

cannot run windows service as unix process

What it means

This panic is a hard guard in the non-Windows build of Litestream (main_notwindows.go). runWindowsService is only meaningful on Windows where the binary runs as a Windows service; on Unix builds it is unreachable by design, so it panics instead. If you see it, platform detection (isWindowsService) on your build incorrectly reported a Windows service context or the wrong build was invoked via that path.

Source

Thrown at cmd/litestream/main_notwindows.go:19

//go:build !windows

package main

import (
	"context"
	"os"
	"os/signal"
	"syscall"
)

const defaultConfigPath = "/etc/litestream.yml"

func isWindowsService() (bool, error) {
	return false, nil
}

func runWindowsService(ctx context.Context) error {
	panic("cannot run windows service as unix process")
}

func signalChan() <-chan os.Signal {
	ch := make(chan os.Signal, 2)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	return ch
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Do not call runWindowsService on Unix; run litestream directly (litestream replicate -config ...) and rely on systemd/launchd for supervision
  2. Verify you are running an unmodified official litestream build; rebuild from a clean checkout
  3. If embedding litestream as a library, use the public API (litestream.NewDB/NewReplica, Store) instead of the CLI/service plumbing

Example fix

// before: embedding code calls CLI internals on Linux
runWindowsService(ctx)
// after: run normally under systemd/launchd
exec.Command("litestream", "replicate", "-config", "/etc/litestream.yml").Run()
Defensive patterns

Strategy: validation

Validate before calling

// Only reach the Windows-service path on Windows builds
if runtime.GOOS == "windows" {
    if isSvc, err := isWindowsService(); err == nil && isSvc {
        return runWindowsService(ctx)
    }
}
return runNormal(ctx)

Type guard

func isUnixBuild() bool { return runtime.GOOS != "windows" } // then never call runWindowsService

Try / catch

// panic is not recoverable by design at this layer; guard the call site
if isSvc, err := isWindowsService(); err != nil {
    return err
} else if isSvc {
    if runtime.GOOS == "windows" {
        return runWindowsService(ctx)
    }
}

Prevention

When it happens

Trigger: Calling cmd/litestream's service-launch path (runWindowsService) on a Unix build. Normally unreachable because isWindowsService() always returns (false, nil) on non-Windows; only a code path change or direct call would reach the panic.

Common situations: Custom forks or patches that modified the isWindowsService check; embedding litestream's main package internals in another program and calling runWindowsService on Linux/macOS; using a binary built from modified source instead of the released binary.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/328572cb560d43be. Report an issue: GitHub.