vercel/ai · error · Error
Invalid Cline history file name: ${historyFileName}
Error message
Invalid Cline history file name: ${historyFileName} What it means
safeClineHistoryFileName validates a Cline session history file name against the strict pattern /^[A-Za-z0-9][A-Za-z0-9._-]*\.json$/ before it is ever used to build a filesystem path. Any name containing path separators, traversal sequences ('..'), leading special characters, or a non-.json extension is rejected to prevent path traversal and arbitrary file access when resuming Cline sessions.
Source
Thrown at packages/harness-cline/src/cline-resume-state.ts:14
import { createHash } from 'node:crypto';
import path from 'node:path';
import {
safeParseJSON,
type Experimental_SandboxSession,
} from '@ai-sdk/provider-utils';
import type { AgentMessage } from '@cline/agents';
import { z } from 'zod/v4';
const CLINE_HISTORY_FILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*\.json$/;
export function safeClineHistoryFileName(historyFileName: string): string {
if (!CLINE_HISTORY_FILE_NAME_PATTERN.test(historyFileName)) {
throw new Error(`Invalid Cline history file name: ${historyFileName}`);
}
return historyFileName;
}
const clineHistoryFileNameSchema = z
.string()
.refine(
historyFileName => CLINE_HISTORY_FILE_NAME_PATTERN.test(historyFileName),
'Cline historyFileName must be a safe .json basename.',
);
/**
* Schema for the adapter-specific portion of lifecycle state `data` produced
* by the Cline harness's resumable lifecycle methods. Carries the basename of
* the serialized conversation history. The actual history bytes live in a
* private, session-scoped directory under sandbox HOME so they survive
* cross-process resume without appearing in the agent workspace.
*/View on GitHub (pinned to 69428b1f8b)
Solutions
- Sanitize the name to the allowed character set and re-add the .json extension before passing it in.
- Strip any directory components — pass only the base file name, never a full path.
- Ensure the extension is lowercase '.json' and the first character is alphanumeric.
- If loading legacy state, rename/normalize history files to the expected pattern before resuming.
Example fix
// before
safeClineHistoryFileName('../etc/passwd'); // Invalid Cline history file name
safeClineHistoryFileName('sub/dir/session.json'); // rejected
// after: validate/sanitize first
function toHistoryFileName(raw) {
const base = raw.split(/[\\/]/).pop() ?? '';
const safe = base.replace(/[^A-Za-z0-9._-]/g, '-');
return safe.endsWith('.json') ? safe : `${safe}.json`;
}
safeClineHistoryFileName(toHistoryFileName('sub/dir/session.json')); // 'session.json' Defensive patterns
Strategy: validation
Validate before calling
const SAFE_HISTORY_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*\.json$/;
function isValidHistoryFileName(name) {
return typeof name === 'string' && SAFE_HISTORY_NAME.test(name);
}
// call before: if (!isValidHistoryFileName(raw)) throw new Error('bad history file name'); Type guard
function isValidClineHistoryFileName(value: unknown): value is string {
return typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._-]*\.json$/.test(value);
} Try / catch
try {
const name = safeClineHistoryFileName(rawName);
return restored(name);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Invalid Cline history file name:')) {
// sanitize: strip directories and illegal chars, re-add .json, then retry
const base = rawName.split(/[\\/]/).pop() ?? '';
const fixed = base.replace(/[^A-Za-z0-9._-]/g, '-').replace(/(\.json)?$/i, '.json');
return restored(safeClineHistoryFileName(fixed));
}
throw e;
} Prevention
- Pass only base file names — never full paths or URLs — into resume helpers.
- Validate history names with the same regex at your API boundary before storage.
- Normalize legacy/foreign state files to the expected naming scheme on migration.
- Treat history file names from untrusted sources (URLs, CLI args) as hostile input.
When it happens
Trigger: Calling cline-resume-state helpers (filePath/restored) with a history file name containing '/' or '\\', starting with '.' or '-', containing other special characters, or not ending in '.json'; loading persisted state written by an older or foreign tool with a different naming scheme.
Common situations: Restoring sessions from hand-edited or third-party state files; names captured from untrusted input (URLs, CLI args) that include path components; migrated history from a previous Cline version using different naming; typos like 'session json' (space) or 'session.JSON' (uppercase extension).
Related errors
- Invalid Cline history file name: ${input.historyFileName}
- Invalid Pi ${label} name: ${name}
- Tool approval signature verification failed for approval "${
- ACP runtime environment key ${JSON.stringify(key)} cannot be
- Invalid Pi session file name: ${input.sessionFileName}
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/c1d2b9cb778d31ab.
Report an issue: GitHub.