{"record":{"id":"4c2ab554dff7f454","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-create-directory-v-4c2ab5","errorCode":null,"errorMessage":"failed to create directory: %v","messagePattern":"failed to create directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/codex/token.go","lineNumber":61,"sourceCode":"func (ts *CodexTokenStorage) SetMetadata(meta map[string]any) {\n\tts.Metadata = meta\n}\n\n// SaveTokenToFile serializes the Codex token storage to a JSON file.\n// This method creates the necessary directory structure and writes the token\n// data in JSON format to the specified file path for persistent storage.\n// It merges any injected metadata into the top-level JSON object.\n//\n// Parameters:\n//   - authFilePath: The full path where the token file should be saved\n//\n// Returns:\n//   - error: An error if the operation fails, nil otherwise\nfunc (ts *CodexTokenStorage) SaveTokenToFile(authFilePath string) error {\n\tmisc.LogSavingCredentials(authFilePath)\n\tts.Type = \"codex\"\n\tif err := os.MkdirAll(filepath.Dir(authFilePath), 0700); err != nil {\n\t\treturn fmt.Errorf(\"failed to create directory: %v\", err)\n\t}\n\n\t// Merge metadata using helper\n\tdata, errMerge := misc.MergeMetadata(ts, ts.Metadata)\n\tif errMerge != nil {\n\t\treturn fmt.Errorf(\"failed to merge metadata: %w\", errMerge)\n\t}\n\n\tf, err := os.Create(authFilePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create token file: %w\", err)\n\t}\n\tdefer func() {\n\t\tif errClose := f.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"codex token storage: close token file error: %v\", errClose)\n\t\t}\n\t}()\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/codex/token.go#L43-L79","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the path in the log line (LogSavingCredentials prints it) and inspect parent permissions: `ls -ld <dir>`.","Pre-create the directory with correct ownership: `mkdir -p <auth-dir> && chown $(id -u) <auth-dir>`.","Fix volume mounts to be rw, or point auth-dir at a writable location.","Remove any regular file occupying a needed directory component.","Run the process as a user permitted to write the auth directory."],"exampleFix":"# before: auth-dir: /var/lib/cliproxy/auths (root-owned, process unprivileged)\n# after\nsudo mkdir -p /var/lib/cliproxy/auths && sudo chown $(whoami) /var/lib/cliproxy/auths","handlingStrategy":"validation","validationCode":"// Ensure the auth directory exists and is writable before starting the flow\ninfo, err := os.Stat(authDir)\nif os.IsNotExist(err) {\n    if err := os.MkdirAll(authDir, 0o700); err != nil { return err }\n} else if err != nil {\n    return err\n} else if !info.IsDir() {\n    return fmt.Errorf(\"%s exists but is a file\", authDir)\n}","typeGuard":null,"tryCatchPattern":"if err := ts.SaveTokenToFile(path); err != nil {\n    if strings.Contains(err.Error(), \"failed to create directory\") {\n        // fix permissions/ownership of the parent dir, then retry the save\n    }\n}","preventionTips":["Pre-create and chown the auth directory as part of deployment.","Mount auth volumes read-write, never read-only.","Smoke-test file creation in the auth dir at startup."],"tags":["filesystem","permissions","storage","auth-flow","codex"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}