JuliusBrussee/caveman · error

native runtime: store is required

Error message

native runtime: store is required

What it means

This guard fires in nativeruntime.Serve on Windows before the named-pipe listener is created. The pipe server answers requests by reading from the Runtime's backing store (Runtime.store, injected via nativeruntime.New/NewWithReceipts), so Serve refuses to start when runtime is nil or its store was never wired. A pipe without the store could not serve the protocol at all, so this is a fail-fast wiring check.

Source

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

	absolute, err := filepath.Abs(home)
	if err != nil {
		absolute = home
	}
	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()

View on GitHub (pinned to 766dce6b13)

Solutions

  1. Find the Serve call site and build the runtime with nativeruntime.New(store) (or NewWithReceipts), passing a store handle that opened successfully.
  2. Propagate the store-open error and abort startup instead of continuing with a nil store.
  3. In wiring/main, log store-open failures distinctly from named-pipe listen failures so this guard never fires in production.

Example fix

// before
runtime := &nativeruntime.Runtime{} // zero value: store == nil
err := nativeruntime.Serve(ctx, home, runtime)

// after
store, err := openCCRSpecStore(home) // must succeed
if err != nil {
	return fmt.Errorf("open ccr store: %w", err)
}
err = nativeruntime.Serve(ctx, home, nativeruntime.New(store))
Defensive patterns

Strategy: validation

Validate before calling

// Before Serve: prove the runtime was constructed with a real store.
if runtime == nil {
	return errors.New("nativeruntime.Serve: runtime is nil; build with nativeruntime.New(store)")
}
// Runtime.store is unexported, so the only safe construction is the constructor:
// ensure the store opened successfully BEFORE calling New.
store, err := openStoreOrFail(home)
if err != nil {
	return err
}
runtime = nativeruntime.New(store)

Prevention

When it happens

Trigger: Calling nativeruntime.Serve(ctx, home, runtime) with a nil *Runtime, or with a Runtime built as a struct literal (zero value, store == nil) instead of nativeruntime.New(store) / NewWithReceipts(store, dir). Typically happens when the store-open step failed earlier, the error was ignored, and wiring continued with a nil handle.

Common situations: Startup code that ignores the error from opening the SQLite/ccr store and passes the result anyway; refactors that move store construction into another function; unit tests that instantiate &Runtime{} directly to save setup.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/dc59aab179b48c39. Report an issue: GitHub.