router-for-me/CLIProxyAPI · error

plugin sync response missing expires_at

Error message

plugin sync response missing expires_at

What it means

The plugin sync response passed validation of schema_version but its expires_at time.Time is the zero value, meaning the field was absent or unparseable in the JSON. Every sync payload must carry a meaningful expiry so stale indexes are never used; a zero value is treated as malformed data.

Source

Thrown at internal/pluginstore/home_sync.go:55

	i.Auth = nil
	i.Manifest = Manifest{}
}

type PluginSyncResponse struct {
	SchemaVersion int              `json:"schema_version"`
	ExpiresAt     time.Time        `json:"expires_at"`
	Items         []PluginSyncItem `json:"items"`
}

func (r *PluginSyncResponse) Validate(now time.Time) error {
	if r == nil {
		return fmt.Errorf("plugin sync response is nil")
	}
	if r.SchemaVersion != PluginSyncSchemaVersion {
		return fmt.Errorf("unsupported plugin sync schema_version %d", r.SchemaVersion)
	}
	if r.ExpiresAt.IsZero() {
		return fmt.Errorf("plugin sync response missing expires_at")
	}
	if !now.Before(r.ExpiresAt) {
		return fmt.Errorf("plugin sync response expired")
	}
	seen := make(map[string]struct{}, len(r.Items))
	for index := range r.Items {
		item := &r.Items[index]
		if errManifest := item.Manifest.Validate(); errManifest != nil {
			return fmt.Errorf("plugin sync item %d: %w", index, errManifest)
		}
		if errURLs := validatePluginSyncManifestURLs(item.Manifest); errURLs != nil {
			return fmt.Errorf("plugin sync item %d: %w", index, errURLs)
		}
		id := strings.TrimSpace(item.Manifest.ID)
		if _, exists := seen[id]; exists {
			return fmt.Errorf("plugin sync response contains duplicate plugin %q", id)
		}
		seen[id] = struct{}{}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Inspect the raw sync JSON and confirm expires_at is present and RFC3339-formatted
  2. Fix the sync server/index generator to always emit expires_at
  3. Re-fetch the index from the official plugin store URL to get a well-formed payload
Defensive patterns

Strategy: validation

Validate before calling

if resp.ExpiresAt.IsZero() {
    return errors.New("sync payload missing expires_at; treat as malformed")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "missing expires_at") {
    // discard payload, refetch; report to index operator if persistent
}

Prevention

When it happens

Trigger: Validate on a sync response where the JSON lacked expires_at, it was null, or the timestamp format was not parseable by encoding/json (non-RFC3339).

Common situations: Hand-crafted or third-party sync indexes omitting expiry; a server bug dropping the field; a timestamp format change on the server.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/a99a9f322b6dfd43. Report an issue: GitHub.