thedotmack/claude-mem · critical · ServerClassifiedProviderError

auth_invalid

auth_invalid

Error message

Anthropic API key not configured

What it means

ClaudeObservationProvider's constructor validates that an Anthropic API key was supplied in its options and throws a ServerClassifiedProviderError with kind 'auth_invalid' when it is missing/empty. The provider cannot authenticate to Anthropic without a key, so it fails fast at construction time.

Solutions

  1. Set the ANTHROPIC_API_KEY environment variable (or the settings location the server reads it from) and restart the server.
  2. Verify the key is actually propagated into the provider options where ClaudeObservationProvider is constructed.
  3. Catch ServerClassifiedProviderError and check err kind === 'auth_invalid' to give the user a clear configuration prompt instead of a crash.

Example fix

// before
new ClaudeObservationProvider({ model: 'claude-sonnet-4' })
// after
new ClaudeObservationProvider({ apiKey: process.env.ANTHROPIC_API_KEY!, model: 'claude-sonnet-4' })
Defensive patterns

Strategy: validation

Validate before calling

if (!process.env.ANTHROPIC_API_KEY) {
  throw new Error('ANTHROPIC_API_KEY must be set before starting the server');
}
new ClaudeObservationProvider({ apiKey: process.env.ANTHROPIC_API_KEY });

Type guard

const hasApiKey = (o: ClaudeObservationProviderOptions): o is ClaudeObservationProviderOptions & { apiKey: string } =>
  typeof o.apiKey === 'string' && o.apiKey.length > 0;

Try / catch

try {
  provider = new ClaudeObservationProvider(opts);
} catch (e) {
  if (e instanceof ServerClassifiedProviderError && e.kind === 'auth_invalid') {
    console.error('Set ANTHROPIC_API_KEY and restart the server.');
  }
}

Prevention

When it happens

Trigger: Constructing new ClaudeObservationProvider(options) with options.apiKey undefined, null, or an empty string — typically because ANTHROPIC_API_KEY was not set when server config was built.

Common situations: Server started without ANTHROPIC_API_KEY in the environment, key removed from settings, or provider options assembled programmatically without passing the credential through.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/65d0b54b4fe87aa9. Report an issue: GitHub.

Appendix: source

Thrown at src/server/generation/providers/ClaudeObservationProvider.ts:47

  fetchImpl?: typeof fetch;
}

interface AnthropicMessagesResponse {
  content?: Array<{ type?: string; text?: string }>;
  usage?: { input_tokens?: number; output_tokens?: number };
  error?: { type?: string; message?: string };
}

export class ClaudeObservationProvider implements ServerGenerationProvider {
  readonly providerLabel = 'claude' as const;
  private readonly apiKey: string;
  private readonly model: string;
  private readonly maxOutputTokens: number;
  private readonly fetchImpl: typeof fetch;

  constructor(options: ClaudeObservationProviderOptions) {
    if (!options.apiKey) {
      throw new ServerClassifiedProviderError('Anthropic API key not configured', {
        kind: 'auth_invalid',
        cause: new Error('apiKey is required'),
      });
    }
    this.apiKey = options.apiKey;
    this.model = options.model ?? DEFAULT_MODEL;
    this.maxOutputTokens = options.maxOutputTokens ?? 4096;
    this.fetchImpl = options.fetchImpl ?? fetch;
  }

  async generate(
    context: ServerGenerationContext,
    signal?: AbortSignal,
  ): Promise<ServerGenerationResult> {
    const { prompt, skippedAll } = buildServerGenerationPrompt(context);
    if (skippedAll) {
      // All events were scrubbed by privacy stripping. Don't bill the
      // provider — return a synthetic skip response that parser accepts.

View on GitHub (pinned to d8bc9755e7)