thedotmack/claude-mem · warning
Anthropic API rejected request with HTTP 400: this model doe
Error message
Anthropic API rejected request with HTTP 400: this model does not support the `effort` parameter. CLAUDE_CODE_EFFORT_LEVEL is likely leaking into the SDK subprocess env via ~/.claude-mem/.env — remove it or scope it to models that support effort. See https://github.com/thedotmack/claude-mem/issues/2357.
What it means
The observer drives the Claude Agent SDK as a subprocess; that subprocess inherits claude-mem's environment, including ~/.claude-mem/.env. When that env contains CLAUDE_CODE_EFFORT_LEVEL and the active model does not support the effort parameter, the Anthropic API rejects requests with HTTP 400; the provider classifier detects the 'effort parameter' marker in the message or body, logs this hint once, and classifies the error as unrecoverable.
Source
Thrown at src/services/worker/ClaudeProvider.ts:138
// the pattern in GeminiProvider.classifyGeminiError / classifyOpenRouterError
// (see #2357: the SDK forwards `effort` to the Messages API when
// CLAUDE_CODE_EFFORT_LEVEL leaks into the subprocess env, and models like
// Haiku/Sonnet 4.5 reject with 400 — without this branch the default
// `transient` classification retried indefinitely).
if (errAny.status === 400) {
// Inspect both the message and any structured body for the effort marker.
const bodyText = (() => {
const body = errAny.body;
if (typeof body === 'string') return body;
if (body && typeof body === 'object') {
try { return JSON.stringify(body); } catch { return ''; }
}
return '';
})();
const haystack = `${message}\n${bodyText}`;
if (/effort parameter/i.test(haystack) && !effortHintLogged) {
effortHintLogged = true;
logger.warn(
'SDK',
'Anthropic API rejected request with HTTP 400: this model does not support the `effort` parameter. ' +
'CLAUDE_CODE_EFFORT_LEVEL is likely leaking into the SDK subprocess env via ~/.claude-mem/.env — ' +
'remove it or scope it to models that support effort. See https://github.com/thedotmack/claude-mem/issues/2357.',
{ status: 400 }
);
}
return new ClassifiedProviderError(
message || 'Anthropic bad request (status 400)',
{ kind: 'unrecoverable', cause: err },
);
}
// Status-less Anthropic 400s — SDK wrapping can drop `.status`, leaving only
// the message or an `invalid_request_error` body; classify those as
// unrecoverable so the worker stops retrying a permanent config error (#2656).
// The status guard keeps statused 4xx/5xx on their own branches.
if (View on GitHub (pinned to 8bc631a71a)
Solutions
- Remove CLAUDE_CODE_EFFORT_LEVEL from ~/.claude-mem/.env and restart the worker
- If you need effort, scope it to a model that supports the parameter (per-model env or settings) instead of the global .env
- Verify the fix by confirming the observer no longer logs 400s and sessions complete
Example fix
# ~/.claude-mem/.env - before CLAUDE_CODE_EFFORT_LEVEL=low # after (line removed) # scope effort per supported model in the SDK settings instead
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
function assertNoLeakedEffortLevel(envPath = path.join(os.homedir(), '.claude-mem', '.env')): void {
if (!fs.existsSync(envPath)) return;
const raw = fs.readFileSync(envPath, 'utf-8');
if (/^\s*CLAUDE_CODE_EFFORT_LEVEL\s*=/m.test(raw)) {
throw new Error('CLAUDE_CODE_EFFORT_LEVEL in ~/.claude-mem/.env breaks models without effort support — remove or scope it');
}
} Try / catch
try {
await runObserverQuery(session);
} catch (error: unknown) {
const msg = error instanceof Error ? error.message : String(error);
if (/effort parameter/i.test(msg)) {
// unrecoverable config issue: strip CLAUDE_CODE_EFFORT_LEVEL from .env, restart worker, do not retry as-is
throw new Error('Remove CLAUDE_CODE_EFFORT_LEVEL from ~/.claude-mem/.env (issue #2357)');
}
throw error;
} Prevention
- Keep model-specific knobs like effort out of the global ~/.claude-mem/.env
- After changing models, re-audit .env for variables the new model does not support
- Restart the worker after env changes so the SDK subprocess inherits the fixed environment
When it happens
Trigger: ~/.claude-mem/.env sets CLAUDE_CODE_EFFORT_LEVEL (e.g. low/medium/high) while the configured model rejects effort; the var was added for a different model and later the model changed; the SDK version started forwarding the var to the API.
Common situations: Users tuning effort for Claude Code in .env then switching observer models; copying a teammate's .env; upgrading the SDK so a previously ignored variable is now honored.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- Bun installation completed but binary not found. Please rest
- Failed to install Bun. Please install manually: ${manualInst
- uv installation completed but binary not found. Please resta
- INVALID_CORPUS_NAME
- Failed to capture session_id while priming corpus "${corpus.
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20).
Data as JSON: /api/errors/f93a87056075683e.
Report an issue: GitHub.