JuliusBrussee/caveman · error

native runtime current user SID: %w

Error message

native runtime current user SID: %w

What it means

Returned when the Windows build of the native runtime cannot read the current process token's user via windows.GetCurrentProcessToken().GetTokenUser(). The SID is required to build the SDDL owner-only ACL on the named pipe, so a failure here aborts Serve before any pipe is created.

Source

Thrown at proxy/internal/nativeruntime/server_windows.go:43

	normalized := strings.ToLower(filepath.Clean(absolute))
	sum := sha256.Sum256([]byte(normalized))
	return `\\.\pipe\caveman-native-` + hex.EncodeToString(sum[:8])
}

func dialNativeRuntime(ctx context.Context, home string) (net.Conn, error) {
	return winio.DialPipeContext(ctx, SocketPath(home))
}

// Serve exposes the same bounded JSON protocol over a user-only Windows named
// pipe. go-winio rejects remote clients at pipe creation; explicit owner SID
// ACL prevents another local user from attaching.
func Serve(ctx context.Context, home string, runtime *Runtime) error {
	if runtime == nil || runtime.store == nil {
		return errors.New("native runtime: store is required")
	}
	user, err := windows.GetCurrentProcessToken().GetTokenUser()
	if err != nil {
		return fmt.Errorf("native runtime current user SID: %w", err)
	}
	if user == nil || user.User.Sid == nil {
		return errors.New("native runtime current user SID: unavailable")
	}
	sddl := "D:P(A;;GA;;;" + user.User.Sid.String() + ")"
	listener, err := winio.ListenPipe(SocketPath(home), &winio.PipeConfig{
		SecurityDescriptor: sddl,
		InputBufferSize:    maxRequestBytes,
		OutputBufferSize:   maxRequestBytes,
	})
	if err != nil {
		return fmt.Errorf("native runtime named-pipe listen: %w", err)
	}
	defer listener.Close()
	go func() {
		<-ctx.Done()
		_ = listener.Close()
	}()

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Run the process under a normal interactive or standard service account rather than a sandboxed/restricted token
  2. If running under a custom service wrapper, ensure it does not strip TOKEN_QUERY from the process token
  3. Verify with a minimal Go program calling windows.GetCurrentProcessToken().GetTokenUser() to isolate environment vs. code issues
  4. Update go-winio / x/sys/windows — token enumeration has had fixes across Windows versions

Example fix

// before: service launcher applies a restricted token, GetTokenUser fails
err := nativeruntime.Serve(ctx, home, rt)

// after: launch without token restriction (normal service account)
// then:
err := nativeruntime.Serve(ctx, home, rt)
Defensive patterns

Strategy: try-catch

Validate before calling

null

Try / catch

if err := nativeruntime.Serve(ctx, home, rt); err != nil {
    if strings.Contains(err.Error(), "current user SID") {
        // environment/token problem, not a code bug: rerun under a normal user token
        log.Error("cannot query process token; run under an unrestricted user account", "error", err)
    }
}

Prevention

When it happens

Trigger: Calling nativeruntime.Serve on Windows when the Win32 API fails to open or query the process token — e.g. restricted tokens under some service contexts, sandboxed processes, or broken privilege-removal in the parent.

Common situations: Running caveman under a heavily restricted service account or job object; Windows sandbox (AppContainer/low integrity) stripping token query rights; unusual terminal-session environments (SSH-into-Windows session 0 quirks) where the token API behaves differently. The adjacent 'SID: unavailable' string fires when the call succeeds but returns a nil user/SID.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/38826f1d7d3b435f. Report an issue: GitHub.