Tencent/WeKnora · warning

mark session %s stale: %w

Error message

mark session %s stale: %w

What it means

InvalidateByConfig marks every binding for a config stale in parallel; the per-session markBindingStale work runs under an acquire timer. If marking one session fails, the error is collected (not returned immediately) as "mark session <id> stale: %w" and joined with other failures via errors.Join. InvalidateByConfig ultimately surfaces the joined error to its caller.

Source

Thrown at internal/sandbox/session_binding.go:232

			}
			if binding.ConfigID != wanted || binding.StaleAt != nil {
				return nil
			}
			wrote, err := store.markBindingStale(
				markCtx, key, *binding, time.Now().UTC(),
			)
			if err != nil {
				return err
			}
			if wrote {
				marked++
			}
			return nil
		})
		acquireTimer.Stop()
		cancel()
		if err != nil {
			failures = append(failures, fmt.Errorf("mark session %s stale: %w", key.SessionID, err))
		}
	}
	return marked, errors.Join(failures...)
}

type lifecycleOwnershipContextKey struct{}

func withLifecycleOwnershipContext(
	ctx context.Context,
	ownershipCtx context.Context,
) context.Context {
	return context.WithValue(ctx, lifecycleOwnershipContextKey{}, ownershipCtx)
}

func lifecycleOwnershipContext(ctx context.Context) context.Context {
	if ownershipCtx, ok := ctx.Value(lifecycleOwnershipContextKey{}).(context.Context); ok {
		return ownershipCtx
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the joined error to find which session IDs failed and retry InvalidateByConfig or targeted marks for those
  2. Increase the acquire/lifecycle-lock timeout or reduce concurrency of invalidation sweeps
  3. Check Redis health/latency; the failures are usually store-side contention or timeouts
  4. Verify no other process holds the lifecycle lock on the affected sessions

Example fix

// before
if err := store.InvalidateByConfig(ctx, tenant, cfg); err != nil {
    log.Fatal(err) // opaque joined error
}
// after
if err := store.InvalidateByConfig(ctx, tenant, cfg); err != nil {
    for _, part := range strings.Split(err.Error(), "\n") {
        log.Warnf("partial invalidate: %s", part) // retry per failed session
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if err := store.Ping(ctx); err != nil {
    return fmt.Errorf("postpone invalidation: store degraded: %w", err)
}

Try / catch

if err := store.InvalidateByConfig(ctx, tenant, cfg); err != nil {
    for _, failure := range strings.Split(err.Error(), "\n") {
        if id, ok := parseFailedSession(failure); ok {
            retryMarkStale(ctx, tenant, cfg, id)
        }
    }
}

Prevention

When it happens

Trigger: Invalidating bindings by config while the store is degraded: Redis timeouts exceeding the acquire deadline, connection pool exhaustion, or a single key being locked by another worker's lifecycle lock.

Common situations: Redis under load during incident-driven mass invalidation; lock contention between concurrent reapers and invalidators; partial network failures hitting only some sessions.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/b85a94b3726c4718. Report an issue: GitHub.