thedotmack/claude-mem · info

is forbidden from tool use (claude-mem hard lockdown).

Error message

${input.source} is forbidden from tool use (claude-mem hard lockdown).

What it means

This is the deny message returned by the hardened SDK canUseTool hook. claude-mem's Observer and KnowledgeAgent sessions are deliberately built with a hard lockdown: every tool use is denied and logged, because these agent sessions must only observe/compress, never act. The message is informational-by-design, not a bug — it records that a tool-use attempt was blocked.

Solutions

  1. If you are a user seeing this in logs: no action needed — the security boundary worked; check the audit log via recordObserverToolAttempt for what was attempted
  2. If you expected real tool use: do not route that workload through buildHardenedSdkOptions/Observer sessions; use a normal interactive session
  3. If you are developing: confirm the call site legitimately should be locked down; do not weaken the deny — adjust the session type instead

Example fix

// before: observer tries to use tools and gets denied
const options = buildHardenedSdkOptions({ source: 'Observer', ... });
// after: use a non-hardened path only when tool use is intentional
const options = buildSdkOptionsForInteractiveAgent({ ... }); // if tool use is expected
Defensive patterns

Strategy: validation

Type guard

function isHardenedSource(s: string): s is 'Observer' | 'KnowledgeAgent' {
  return s === 'Observer' || s === 'KnowledgeAgent';
}

Try / catch

if (result.behavior === 'deny') {
  logger.warn('Tool use denied by hard lockdown:', result.message);
  // continue without executing the tool; do not retry
}

Prevention

When it happens

Trigger: Any Observer or KnowledgeAgent SDK session (built via buildHardenedSdkOptions) attempts to call ANY tool (Bash, Write, WebFetch, etc.), triggering the canUseTool callback which unconditionally returns behavior:'deny'.

Common situations: Model spontaniously tries to run Bash or edit a file during an observation session; a prompt injection in watched content convinces the observer to call a tool; misconfigured session that was meant to be an interactive Claude session got built with hardened options.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/sdk/hardened-options.ts:145

  const canUseTool: Options['canUseTool'] = async (toolName, toolInput) => {
    recordObserverToolAttempt({
      source: input.source,
      sessionDbId: input.sessionDbId,
      contentSessionId: input.contentSessionId,
      project: input.project,
      tool_name: toolName,
      tool_input: toolInput,
      result: 'denied',
    });
    // Real-time visibility for the persistent audit trail. The append-only log
    // (recordObserverToolAttempt above) is the authoritative record; this WARN
    // surfaces the attempt in the live worker log for incident detection.
    logger.warn('SECURITY', `Blocked tool use by ${input.source}: ${toolName}`, {
      sessionId: input.sessionDbId,
      source: input.source,
      tool_name: toolName,
    });
    return {
      behavior: 'deny',
      message: `${input.source} is forbidden from tool use (claude-mem hard lockdown).`,
    };
  };

  return {
    model: input.model,
    cwd: input.cwd ?? OBSERVER_SESSIONS_DIR,
    env: input.env,
    pathToClaudeCodeExecutable: input.pathToClaudeCodeExecutable,
    ...(input.abortController ? { abortController: input.abortController } : {}),
    ...(input.resume ? { resume: input.resume } : {}),
    ...(input.spawnClaudeCodeProcess ? { spawnClaudeCodeProcess: input.spawnClaudeCodeProcess } : {}),
    // Observer thinking is behavior-only and does not participate in the lockdown boundary.
    ...(input.source === 'Observer' ? { thinkingConfig: { type: 'disabled' as const } } : {}),

    // === Tool lockdown (defense-in-depth) ===
    tools: [],                                        // belt: disable ALL built-in tools

View on GitHub (pinned to d8bc9755e7)