router-for-me/CLIProxyAPI · error

failed to create directory: %v

Error message

failed to create directory: %v

What it means

Returned by KimiTokenStorage.SaveTokenToFile when os.MkdirAll on the parent directory of the auth file path fails (internal/auth/kimi/kimi/token.go:86-88). The proxy creates auths/<name>.json for Kimi credentials and must create the directory first; failure is a filesystem-level problem such as a read-only volume or missing permissions.

Source

Thrown at internal/auth/kimi/token.go:88

	// UserCode is the code the user must enter at the verification URI.
	UserCode string `json:"user_code"`
	// VerificationURI is the URL where the user should enter the code.
	VerificationURI string `json:"verification_uri,omitempty"`
	// VerificationURIComplete is the URL with the code pre-filled.
	VerificationURIComplete string `json:"verification_uri_complete"`
	// ExpiresIn is the number of seconds until the device code expires.
	ExpiresIn int `json:"expires_in"`
	// Interval is the minimum number of seconds to wait between polling requests.
	Interval int `json:"interval"`
}

// SaveTokenToFile serializes the Kimi token storage to a JSON file.
func (ts *KimiTokenStorage) SaveTokenToFile(authFilePath string) error {
	misc.LogSavingCredentials(authFilePath)
	ts.Type = "kimi"

	if err := os.MkdirAll(filepath.Dir(authFilePath), 0700); err != nil {
		return fmt.Errorf("failed to create directory: %v", err)
	}

	// Merge metadata using helper
	data, errMerge := misc.MergeMetadata(ts, ts.Metadata)
	if errMerge != nil {
		return fmt.Errorf("failed to merge metadata: %w", errMerge)
	}

	f, err := os.Create(authFilePath)
	if err != nil {
		return fmt.Errorf("failed to create token file: %w", err)
	}
	defer func() {
		if errClose := f.Close(); errClose != nil {
			log.Errorf("kimi token storage: close token file error: %v", errClose)
		}
	}()

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check the auth file path config (auths dir) and ensure the full parent path exists and is writable: mkdir -p auths && chown $(whoami) auths
  2. If in Docker, mount the auths directory read-write (e.g. -v ./auths:/app/auths) instead of read-only
  3. Verify no regular file occupies any path component of the target directory
  4. Run with a user that has write permission on the parent directory (0700 perms are requested)

Example fix

# before: container runs with read-only root filesystem and no writable auths mount
docker run --read-only ... cli-proxy-api
# after: mount a writable auths volume
docker run --read-only -v "$PWD/auths:/app/auths" ... cli-proxy-api
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(authFilePath)
if info, err := os.Stat(dir); err == nil && !info.IsDir() {
    return fmt.Errorf("auth path parent %q is not a directory", dir)
}
if err := os.MkdirAll(dir, 0700); err != nil {
    return fmt.Errorf("cannot prepare auth dir %q: %w", dir, err)
}

Try / catch

if err := ts.SaveTokenToFile(path); err != nil {
    if strings.Contains(err.Error(), "failed to create directory") {
        log.Errorf("auth dir not writable: %s; fix mounts/permissions", filepath.Dir(path))
    }
    return err
}

Prevention

When it happens

Trigger: Auth directory path (filepath.Dir(authFilePath)) pointing somewhere unwritable: /auths on a read-only rootfs, a path under a directory owned by another user, Docker mount lacking write permission, or a path component that is actually a file.

Common situations: Running the CLIProxyAPI container with a read-only or incorrectly mounted volume for auths/; running as a non-root user against a root-owned directory; misconfigured auth-dir in config.yaml pointing at a nonexistent drive/path.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/9880f90d05084922. Report an issue: GitHub.