{"record":{"id":"d6ade0f143cba50b","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-create-token-file-w-d6ade0","errorCode":null,"errorMessage":"failed to create token file: %w","messagePattern":"failed to create token file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/kimi/token.go","lineNumber":99,"sourceCode":"\n// SaveTokenToFile serializes the Kimi token storage to a JSON file.\nfunc (ts *KimiTokenStorage) SaveTokenToFile(authFilePath string) error {\n\tmisc.LogSavingCredentials(authFilePath)\n\tts.Type = \"kimi\"\n\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(\"kimi token storage: close token file error: %v\", errClose)\n\t\t}\n\t}()\n\n\tencoder := json.NewEncoder(f)\n\tencoder.SetIndent(\"\", \"  \")\n\tif err = encoder.Encode(data); err != nil {\n\t\treturn fmt.Errorf(\"failed to write token to file: %w\", err)\n\t}\n\treturn nil\n}\n\n// IsExpired checks if the token has expired.\nfunc (ts *KimiTokenStorage) IsExpired() bool {\n\tif ts.Expired == \"\" {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/kimi/token.go#L81-L117","documentation":"Returned by KimiTokenStorage.SaveTokenToFile when os.Create fails on the target auth file path (token.go:98-100). The directory was created successfully just before, so the failure is specific to the file itself: permission denied on the directory, path is a directory, name too long, or disk full.","triggerScenarios":"authFilePath points at an existing directory; the parent directory exists but lacks write permission for the process user; filesystem out of space or inodes; the file already exists as an immutable/locked file.","commonSituations":"auths/ owned by root while the proxy runs unprivileged; a leftover directory named like the target token file (e.g. auths/kimi-xxx.json/); full disk in a container; SELinux denying creation.","solutions":["Verify the path is a regular file location, not an existing directory: ls -la auths/","Grant write permission on the directory to the running user: chown -R appuser: auths/ && chmod 700 auths/","Check disk space and inodes: df -h && df -i","On SELinux systems, check the audit log and fix the context of the auths directory"],"exampleFix":"# before\nls -la auths/   # shows kimi-token.json is a DIRECTORY\n# after\nrm -rf auths/kimi-token.json   # remove the directory so os.Create can make a file","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(authFilePath); err == nil && info.IsDir() {\n    return fmt.Errorf(\"auth file path %q is a directory\", authFilePath)\n}","typeGuard":null,"tryCatchPattern":"if err := ts.SaveTokenToFile(path); err != nil {\n    if strings.Contains(err.Error(), \"failed to create token file\") {\n        log.Errorf(\"cannot write %s: check perms/disk\", path)\n    }\n    return err\n}","preventionTips":["Ensure no directories share names with intended token files under auths/","Run the process as the owner of the auths directory","Verify with touch auths/.write-test at startup"],"tags":["filesystem","kimi","auth","permissions"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}