router-for-me/CLIProxyAPI · error
plugin executor %s refresh returned invalid auth data
Error message
plugin executor %s refresh returned invalid auth data
What it means
The plugin's RefreshAuth returned data, the host normalized it via AuthDataToCoreAuth, and the result was nil — meaning the plugin's refreshed auth payload is structurally invalid (e.g. missing file name/type, unparseable storage JSON, or empty required identity fields), so no usable core Auth could be constructed.
Source
Thrown at internal/pluginhost/adapters_executors.go:752
}
if len(data.Metadata) == 0 && auth != nil {
data.Metadata = cloneAnyMap(auth.Metadata)
}
if len(data.Attributes) == 0 && auth != nil {
data.Attributes = cloneStringMap(auth.Attributes)
}
if len(data.StorageJSON) == 0 {
data.StorageJSON = storageJSONFromAuth(auth)
}
if pluginResp.NextRefreshAfter.IsZero() && auth != nil {
data.NextRefreshAfter = auth.NextRefreshAfter
}
if !pluginResp.NextRefreshAfter.IsZero() {
data.NextRefreshAfter = pluginResp.NextRefreshAfter
}
next := a.host.AuthDataToCoreAuth(data, "", data.FileName)
if next == nil {
return nil, fmt.Errorf("plugin executor %s refresh returned invalid auth data", a.Identifier())
}
if auth != nil {
next.CreatedAt = auth.CreatedAt
next.UpdatedAt = auth.UpdatedAt
}
return next, nil
}
func (a *executorAdapter) CountTokens(ctx context.Context, auth *coreauth.Auth, req coreexecutor.Request, opts coreexecutor.Options) (resp coreexecutor.Response, err error) {
if a == nil || a.executor == nil || a.host.isPluginFused(a.pluginID) || !a.host.pluginIdentityCurrent(a.pluginID, a.path, a.version) {
return coreexecutor.Response{}, fmt.Errorf("plugin executor %s is unavailable", a.Identifier())
}
defer func() {
if recovered := recover(); recovered != nil {
a.host.fusePlugin(a.pluginID, "Executor.CountTokens", recovered)
resp = coreexecutor.Response{}
err = fmt.Errorf("plugin executor %s count tokens panic: %v", a.Identifier(), recovered)
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Log/inspect the plugin's raw RefreshAuth response payload (data) to see which required fields are empty or malformed
- Fix the plugin to return complete refresh data: valid StorageJSON, FileName, provider and ID consistent with the auth being refreshed
- Align the plugin with the host's plugin API version (check AuthDataToCoreAuth requirements) and rebuild
- If the plugin cannot be fixed quickly, bypass plugin refresh by re-authenticating the provider natively
Defensive patterns
Strategy: validation
Validate before calling
// Before accepting the plugin build, verify its refresh output round-trips:
func validRefreshPayload(p pluginapi.AuthRefreshResponse) error {
if p.StorageJSON == nil || len(p.StorageJSON) == 0 { return errors.New("empty StorageJSON") }
if strings.TrimSpace(p.FileName) == "" { return errors.New("empty FileName") }
var probe map[string]any
return json.Unmarshal(p.StorageJSON, &probe)
} Prevention
- Contract-test RefreshAuth responses with example payloads in CI
- Pin plugin and host to matching pluginapi versions
- Validate plugin responses at the boundary before converting to core auth
When it happens
Trigger: A plugin RefreshAuth response whose StorageJSON/FileName/attributes are empty or malformed such that AuthDataToCoreAuth returns nil; note the code backfills empty StorageJSON and NextRefreshAfter from the old auth first, so nil usually means the plugin-supplied fields themselves are invalid.
Common situations: Plugin returns an empty or partially-filled refresh response; plugin writes a different auth schema than the host's AuthDataToCoreAuth expects; plugin API version mismatch between plugin and host.
Related errors
- plugin executor %s refresh panic: %v
- auth provider start login panic: %v
- auth provider poll login panic: %v
- plugin auth provider refresh is unavailable for provider %s
- missing access_token and refresh_token
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/364417f3542fa2e9.
Report an issue: GitHub.