router-for-me/CLIProxyAPI · error
pluginhost: token store unavailable
Error message
pluginhost: token store unavailable
What it means
When a plugin's command-line execution returns auth data to persist, the host looks up the SDK token store via sdkAuth.GetTokenStore(). If no token store has been initialized in the process, persistence is aborted with this error and the plugin's returned credentials are not saved.
Source
Thrown at internal/pluginhost/command_line.go:371
return pluginapi.CommandLineExecutionResponse{}, nil
}
defer func() {
if recovered := recover(); recovered != nil {
h.fusePlugin(record.id, "CommandLinePlugin.ExecuteCommandLine", recovered)
resp = pluginapi.CommandLineExecutionResponse{}
err = fmt.Errorf("command-line execution panic: %v", recovered)
}
}()
return plugin.ExecuteCommandLine(ctx, req)
}
func (h *Host) persistCommandLineAuths(ctx context.Context, auths []pluginapi.AuthData) ([]string, error) {
if len(auths) == 0 {
return nil, nil
}
store := sdkAuth.GetTokenStore()
if store == nil {
return nil, fmt.Errorf("pluginhost: token store unavailable")
}
summary := h.hostConfigSummary()
if summary.AuthDir != "" {
if setter, okSetter := store.(interface{ SetBaseDir(string) }); okSetter {
setter.SetBaseDir(summary.AuthDir)
}
}
savedPaths := make([]string, 0, len(auths))
for index, authData := range auths {
record := h.AuthDataToCoreAuth(authData, "", "")
if record == nil {
return savedPaths, fmt.Errorf("pluginhost: command-line auth %d is invalid", index+1)
}
savedPath, errSave := store.Save(ctx, record)
if errSave != nil {
return savedPaths, fmt.Errorf("pluginhost: save command-line auth %s: %w", record.ID, errSave)
}
if strings.TrimSpace(savedPath) != "" {View on GitHub (pinned to 78f0c4079e)
Solutions
- Initialize the token store before running command-line plugin flows (set it up via the SDK's builder/service initialization so GetTokenStore returns non-nil).
- If embedding, follow the standard service bootstrap in sdk/cliproxy rather than constructing the plugin host standalone.
- In tests, install an in-memory token store before invoking command-line execution.
Example fix
// before: host runs command-line flow, store never initialized resp, err := host.ExecuteCommandLine(ctx, req) // persistCommandLineAuths -> "pluginhost: token store unavailable" // after: initialize the store during service bootstrap store := filestore.New(authDir) sdkAuth.SetTokenStore(store) // or equivalent builder option resp, err := host.ExecuteCommandLine(ctx, req)
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the token store exists before running command-line flows
if sdkAuth.GetTokenStore() == nil {
return fmt.Errorf("token store not initialized; initialize auth storage before plugin command-line flows")
} Type guard
func tokenStoreReady() bool {
return sdkAuth.GetTokenStore() != nil
} Try / catch
paths, err := host.PersistCommandLineAuths(ctx, auths)
if err != nil && strings.Contains(err.Error(), "token store unavailable") {
// Non-retryable setup error: initialize store, then re-run the whole command-line flow
return initializeStoreAndRetry()
} Prevention
- Bootstrap auth storage during service init, before any plugin is loaded.
- In embeddings, use the full sdk/cliproxy builder so the token store is always wired.
When it happens
Trigger: Running a plugin command-line flow (plugin.ExecuteCommandLine returning non-empty auths) in a context where the SDK token store was never initialized — e.g. a minimal embedding of the SDK that skipped token store setup, or a host started in a mode that does not register a store.
Common situations: Embedding sdk/cliproxy in a custom binary without configuring auth persistence; running management/command-line tooling before the service fully initializes; a test harness that spins up the plugin host without the auth store.
Related errors
- core auth manager unavailable
- auth provider panic: %v
- auth provider %s returned auth without provider
- auth provider %s returned invalid auth data
- auth provider start login panic: %v
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/ffdcb48e9dc5986f.
Report an issue: GitHub.