JuliusBrussee/caveman · warning

native session key read: %w

Error message

native session key read: %w

What it means

Another process won the O_EXCL race (ErrExist), but reading the just-created session.key then failed. The file was created by a concurrent startup that is mid-write, was removed between the create attempt and the read, or is unreadable due to permissions. LoadOrCreateSessionKey cannot proceed without the shared key bytes.

Source

Thrown at proxy/internal/nativeruntime/marker.go:58

			_ = os.Remove(path)
			return nil, fmt.Errorf("native session key write: %w", writeErr)
		}
		if syncErr := file.Sync(); syncErr != nil {
			_ = file.Close()
			_ = os.Remove(path)
			return nil, fmt.Errorf("native session key sync: %w", syncErr)
		}
		if closeErr := file.Close(); closeErr != nil {
			return nil, fmt.Errorf("native session key close: %w", closeErr)
		}
		return key, nil
	}
	if !errors.Is(err, os.ErrExist) {
		return nil, fmt.Errorf("native session key create: %w", err)
	}
	key, err = os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("native session key read: %w", err)
	}
	if len(key) != sessionKeyBytes {
		return nil, fmt.Errorf("native session key length = %d, want %d", len(key), sessionKeyBytes)
	}
	if err := os.Chmod(path, 0o600); err != nil {
		return nil, fmt.Errorf("native session key chmod: %w", err)
	}
	return key, nil
}

// SessionMarker builds model-temporary correlation context. Local proxy removes
// valid markers byte-surgically before provider inspection or forwarding.
func SessionMarker(key []byte, sessionID string) (string, error) {
	if len(key) != sessionKeyBytes || sessionID == "" || len(sessionID) > 256 {
		return "", errors.New("native session marker: invalid key or session id")
	}
	encoded := base64.RawURLEncoding.EncodeToString([]byte(sessionID))
	sig := markerMAC(key, encoded)

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Retry startup once after a short delay — the winning process finishes writing 32 bytes almost immediately
  2. If persistent, check ownership/permissions on <home>/runtime/session.key (must be readable by the running user, 0600)
  3. Ensure only one user account uses a given home directory
Defensive patterns

Strategy: retry

Try / catch

key, err := nativeruntime.LoadOrCreateSessionKey(home)
if err != nil && strings.Contains(err.Error(), "session key read") {
    time.Sleep(100 * time.Millisecond) // concurrent first-start writer finishes
    key, err = nativeruntime.LoadOrCreateSessionKey(home)
}

Prevention

When it happens

Trigger: Two caveman processes starting simultaneously: the loser of the O_EXCL race reads before the winner finishes writing; antivirus/backup transiently locking the file; another user's 0600 key file read by this user.

Common situations: CLI adapter and proxy starting in parallel (the documented shared-key design); shell profiles launching multiple agents at login.

Related errors


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