router-for-me/CLIProxyAPI · error

failed to create directory: %v

Error message

failed to create directory: %v

What it means

os.MkdirAll failed creating the parent directory of the auth file path (default under auths/) with mode 0700. The error message uses %v rather than %w, so the cause is embedded as text, not wrapped. Typical causes are permission denied on the parent, a read-only filesystem, or a path segment that exists as a regular file.

Source

Thrown at internal/auth/codex/token.go:61

func (ts *CodexTokenStorage) SetMetadata(meta map[string]any) {
	ts.Metadata = meta
}

// SaveTokenToFile serializes the Codex token storage to a JSON file.
// This method creates the necessary directory structure and writes the token
// data in JSON format to the specified file path for persistent storage.
// It merges any injected metadata into the top-level JSON object.
//
// Parameters:
//   - authFilePath: The full path where the token file should be saved
//
// Returns:
//   - error: An error if the operation fails, nil otherwise
func (ts *CodexTokenStorage) SaveTokenToFile(authFilePath string) error {
	misc.LogSavingCredentials(authFilePath)
	ts.Type = "codex"
	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("codex token storage: close token file error: %v", errClose)
		}
	}()

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check the path in the log line (LogSavingCredentials prints it) and inspect parent permissions: `ls -ld <dir>`.
  2. Pre-create the directory with correct ownership: `mkdir -p <auth-dir> && chown $(id -u) <auth-dir>`.
  3. Fix volume mounts to be rw, or point auth-dir at a writable location.
  4. Remove any regular file occupying a needed directory component.
  5. Run the process as a user permitted to write the auth directory.

Example fix

# before: auth-dir: /var/lib/cliproxy/auths (root-owned, process unprivileged)
# after
sudo mkdir -p /var/lib/cliproxy/auths && sudo chown $(whoami) /var/lib/cliproxy/auths
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the auth directory exists and is writable before starting the flow
info, err := os.Stat(authDir)
if os.IsNotExist(err) {
    if err := os.MkdirAll(authDir, 0o700); err != nil { return err }
} else if err != nil {
    return err
} else if !info.IsDir() {
    return fmt.Errorf("%s exists but is a file", authDir)
}

Try / catch

if err := ts.SaveTokenToFile(path); err != nil {
    if strings.Contains(err.Error(), "failed to create directory") {
        // fix permissions/ownership of the parent dir, then retry the save
    }
}

Prevention

When it happens

Trigger: Running the process as a user without write access to the configured auth-dir; auths path configured inside a read-only volume/mount; a file exists where a directory component is needed (e.g. ./auths is a file); disk/inode exhaustion in rare cases.

Common situations: Running in Docker with an incorrectly mounted volume (read-only); config.yaml auth-dir pointing at a root-owned path while the server runs unprivileged; leftover file blocking directory creation after config change.

Related errors


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