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
- Do not call runWindowsService on Unix; run litestream directly (litestream replicate -config ...) and rely on systemd/launchd for supervision
- Verify you are running an unmodified official litestream build; rebuild from a clean checkout
- 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
- Never call runWindowsService from non-Windows code paths; check runtime.GOOS first
- Run litestream on Unix via systemd/launchd instead of a service wrapper
- Build from the official source; avoid patches that alter isWindowsService
- When embedding, use the litestream library API, not cmd/litestream internals
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
- config file not found
- invalid -timestamp, must specify in ISO 8601 format (e.g. 20
- database path required
- database does not exist: %w
- open database: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/328572cb560d43be.
Report an issue: GitHub.