{"record":{"id":"c9a19aad0914235d","repo":"router-for-me/CLIProxyAPI","slug":"pluginhost-save-command-line-auth-s-w","errorCode":null,"errorMessage":"pluginhost: save command-line auth %s: %w","messagePattern":"pluginhost: save command-line auth (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginhost/command_line.go","lineNumber":387,"sourceCode":"\tstore := sdkAuth.GetTokenStore()\n\tif store == nil {\n\t\treturn nil, fmt.Errorf(\"pluginhost: token store unavailable\")\n\t}\n\tsummary := h.hostConfigSummary()\n\tif summary.AuthDir != \"\" {\n\t\tif setter, okSetter := store.(interface{ SetBaseDir(string) }); okSetter {\n\t\t\tsetter.SetBaseDir(summary.AuthDir)\n\t\t}\n\t}\n\tsavedPaths := make([]string, 0, len(auths))\n\tfor index, authData := range auths {\n\t\trecord := h.AuthDataToCoreAuth(authData, \"\", \"\")\n\t\tif record == nil {\n\t\t\treturn savedPaths, fmt.Errorf(\"pluginhost: command-line auth %d is invalid\", index+1)\n\t\t}\n\t\tsavedPath, errSave := store.Save(ctx, record)\n\t\tif errSave != nil {\n\t\t\treturn savedPaths, fmt.Errorf(\"pluginhost: save command-line auth %s: %w\", record.ID, errSave)\n\t\t}\n\t\tif strings.TrimSpace(savedPath) != \"\" {\n\t\t\tsavedPaths = append(savedPaths, savedPath)\n\t\t}\n\t}\n\treturn savedPaths, nil\n}\n\nfunc appendCommandLineSavedPaths(stdout []byte, savedPaths []string) []byte {\n\tif len(savedPaths) == 0 {\n\t\treturn stdout\n\t}\n\tout := append([]byte(nil), stdout...)\n\tif len(out) > 0 && out[len(out)-1] != '\\n' {\n\t\tout = append(out, '\\n')\n\t}\n\tfor _, savedPath := range savedPaths {\n\t\tif strings.TrimSpace(savedPath) == \"\" {","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/command_line.go#L369-L405","documentation":"This wraps a failure from tokenStore.Save while persisting one of the auths returned by a plugin command-line run; %s is the auth record's ID. The underlying error (via %w) explains the real cause — usually a filesystem problem in the auth directory or a serialization failure.","triggerScenarios":"store.Save failing: auth directory not writable or missing, disk full, path permission issues, or the store rejecting the record. Entries before this one were already saved, so the batch is partially applied.","commonSituations":"Running the service with an auths/ directory owned by another user; containers with read-only volumes for auth data; auth dir relocated via config to a path that does not exist; SELinux/AppArmor denying writes.","solutions":["Read the wrapped error — it distinguishes permission problems from encoding problems.","Verify the auth directory (config auth-dir, default auths/) exists and is writable by the process user: ls -ld and touch a test file.","Fix ownership/permissions (chown/chmod) or mount a writable volume in containers.","Re-run the command-line flow; note earlier auths may already be saved, so clean duplicates if the plugin cannot resume."],"exampleFix":"# before: auth dir not writable\n$ ls -ld /etc/cliproxy/auths\ndrwxr-xr-x 2 root root ... /etc/cliproxy/auths\n\n# after\n$ sudo chown -R cliproxy:cliproxy /etc/cliproxy/auths\n$ ./cli-proxy-api <plugin command-line flow>","handlingStrategy":"try-catch","validationCode":"// Pre-flight the auth directory\ninfo, err := os.Stat(authDir)\nif err != nil || !info.IsDir() {\n    return fmt.Errorf(\"auth dir %s missing\", authDir)\n}\nif err := os.WriteFile(filepath.Join(authDir, \".write-check\"), nil, 0o600); err != nil {\n    return fmt.Errorf(\"auth dir %s not writable\", authDir)\n}","typeGuard":"func authDirWritable(dir string) bool {\n    f, err := os.CreateTemp(dir, \".probe-*\")\n    if err != nil {\n        return false\n    }\n    f.Close()\n    os.Remove(f.Name())\n    return true\n}","tryCatchPattern":"paths, err := host.PersistCommandLineAuths(ctx, auths)\nif err != nil && strings.Contains(err.Error(), \"save command-line auth\") {\n    cause := errors.Unwrap(err) // real filesystem error\n    if os.IsPermission(cause) {\n        return fixPermissionsAndRetry(authDir, auths)\n    }\n    return err\n}","preventionTips":["Health-check the auth directory writability at startup, not at first save.","Run the service under a user that owns the auth directory.","Mount auth volumes read-write in containers."],"tags":["plugin","auth","filesystem","permissions","pluginhost"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}