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
- Check the auth file path config (auths dir) and ensure the full parent path exists and is writable: mkdir -p auths && chown $(whoami) auths
- If in Docker, mount the auths directory read-write (e.g. -v ./auths:/app/auths) instead of read-only
- Verify no regular file occupies any path component of the target directory
- 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
- Pre-create and chown the auths directory in deployment scripts
- Mount auths/ read-write in containers
- Add a startup probe that writes a temp file under the auth dir and fails fast
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
- failed to create token file: %w
- failed to update source auth file: %w
- failed to create directory: %v
- failed to write token to file: %w
- vertex credential: create directory failed: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/9880f90d05084922.
Report an issue: GitHub.