thedotmack/claude-mem · error
Refusing inject write outside agent memory/log
Error message
Refusing inject write outside agent memory/log
What it means
assertSafeInjectPath confines all writes to the directory agentDataRoot/agents/<agentId>/memory/log. If the resolved path's parent directory differs from that expected directory, it throws, blocking writes anywhere else on the filesystem (traversal/symlink protection).
Solutions
- Always build the target path with injectLogPath(agentDataRoot, agentId) so it lands inside memory/log.
- Remove any '..' segments or user-supplied path components from the target before calling.
- Verify agentDataRoot matches the actual (realpath'd) root so expectedDir equals the resolved dirname.
Example fix
// before const p = path.join(root, 'agents', agentId, 'memory', 'logs', 'inject.md'); // after const p = injectLogPath(root, agentId); // .../memory/log/<INJECT_LOG_BASENAME>
Defensive patterns
Strategy: validation
Validate before calling
const expected = path.resolve(path.join(root, 'agents', agentId, 'memory', 'log'));
if (path.dirname(path.resolve(target)) !== expected) {
throw new Error('target escapes agent memory/log');
} Try / catch
try {
assertSafeInjectPath(root, agentId, target);
} catch (err) {
logger.error('Refusing unsafe inject path', { target }, err);
return;
} Prevention
- Never interpolate user input into the target path.
- Use injectLogPath() as the single source of valid targets.
- Be aware of symlinks: resolve real paths before validating.
When it happens
Trigger: refreshSeatIndex or ensureIndexLogDir passes a filePath whose path.resolve'd dirname is not exactly the agent's memory/log directory — e.g. paths containing '..', absolute paths to other folders, or symlinked locations that resolve elsewhere.
Common situations: Caller joins a user-supplied subpath; agent data root was moved or symlinked so realpath diverges; a typo passes 'logs' instead of 'log'.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Access denied: " " resolves outside the workspace ( ). MCP…
- Refusing inject path for non-UUID agent id
- Admin endpoints are only accessible from localhost
- Bun installation completed but binary not found. Please…
- Cannot lazy-spawn worker: Bun runtime not found on PATH
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/b6464899d657503d.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/integrations/grok-bot-index-format.ts:175
export function shouldRewriteInject(existingContents: string, nextContents: string): boolean {
return factBlock(existingContents) !== factBlock(nextContents);
}
export function injectLogPath(agentDataRoot: string, agentId: string): string {
if (!AGENT_ID_RE.test(agentId)) {
throw new Error(`Refusing inject path for non-UUID agent id: ${agentId}`);
}
return path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', INJECT_LOG_BASENAME);
}
export function assertSafeInjectPath(agentDataRoot: string, agentId: string, filePath: string): void {
const expectedDir = path.resolve(path.join(agentDataRoot, 'agents', agentId, 'memory', 'log'));
const resolved = path.resolve(filePath);
if (path.basename(resolved).toLowerCase() === 'profile.md') {
throw new Error('Refusing write to profile.md');
}
if (path.dirname(resolved) !== expectedDir) {
throw new Error('Refusing inject write outside agent memory/log');
}
if (path.basename(resolved) !== INJECT_LOG_BASENAME) {
throw new Error(`Refusing inject write to a file this writer does not own: ${path.basename(resolved)}`);
}
}
function writeFileAtomic(filePath: string, contents: string): void {
mkdirSync(path.dirname(filePath), { recursive: true });
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
writeFileSync(tmp, contents, 'utf8');
renameSync(tmp, filePath);
}
export function writeFileIfChanged(filePath: string, contents: string): { changed: boolean; filePath: string } {
if (existsSync(filePath) && readFileSync(filePath, 'utf8') === contents) {
return { changed: false, filePath };
}
writeFileAtomic(filePath, contents);View on GitHub (pinned to d8bc9755e7)