JuliusBrussee/caveman · error

native session key mkdir: %w

Error message

native session key mkdir: %w

What it means

LoadOrCreateSessionKey creates <home>/runtime with mode 0700 before writing the shared HMAC session key. This error means MkdirAll failed — typically a permission problem on the parent directory, a read-only filesystem, or a path component that exists as a file instead of a directory.

Source

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

	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
)

const sessionKeyBytes = 32

var markerPattern = regexp.MustCompile(`\[\[caveman-session-v1 sid="([A-Za-z0-9_-]{1,384})" sig="([0-9a-f]{64})"\]\]`)

// LoadOrCreateSessionKey returns one user-only HMAC key shared by CLI adapters
// and local proxy. O_EXCL makes concurrent first startup converge on one key.
func LoadOrCreateSessionKey(home string) ([]byte, error) {
	dir := filepath.Join(home, "runtime")
	if err := os.MkdirAll(dir, 0o700); err != nil {
		return nil, fmt.Errorf("native session key mkdir: %w", err)
	}
	if err := os.Chmod(dir, 0o700); err != nil {
		return nil, fmt.Errorf("native session key chmod dir: %w", err)
	}
	path := filepath.Join(dir, "session.key")
	key := make([]byte, sessionKeyBytes)
	if _, err := rand.Read(key); err != nil {
		return nil, fmt.Errorf("native session key random: %w", err)
	}
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
	if err == nil {
		if _, writeErr := file.Write(key); writeErr != nil {
			_ = file.Close()
			_ = os.Remove(path)
			return nil, fmt.Errorf("native session key write: %w", writeErr)
		}
		if syncErr := file.Sync(); syncErr != nil {
			_ = file.Close()

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Check the underlying error: 'not a directory' means a file occupies <home>/runtime — remove or rename it
  2. 'permission denied' means fix ownership/permissions: chown the home dir to the running user, or chmod to allow writes
  3. Set HOME (or the equivalent home argument) to a writable per-user directory
  4. On read-only filesystems, point home at a writable volume

Example fix

# before
$ ls -la ~/.caveman
runtime    # a regular file -> Error[1066]

# after
$ rm ~/.caveman/runtime && mkdir -p ~/.caveman/runtime && chmod 700 ~/.caveman/runtime
Defensive patterns

Strategy: validation

Validate before calling

func homeWritable(home string) error {
    fi, err := os.Stat(filepath.Join(home, "runtime"))
    if err == nil && !fi.IsDir() {
        return fmt.Errorf("%s exists but is not a directory", fi.Name())
    }
    if err != nil && !os.IsNotExist(err) {
        return err
    }
    return nil
}

Prevention

When it happens

Trigger: home points at a directory the process cannot write (owned by root, mode 0755 with different user); <home>/runtime already exists as a regular file; running with HOME unset so home resolves to an invalid path; container with a read-only volume mounted at home.

Common situations: Running the proxy/CLI under a service user whose HOME differs from expectations; stale 'runtime' file left by a bad install; immutable container filesystems.

Related errors


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