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

  1. Sanitize the name to the allowed character set and re-add the .json extension before passing it in.
  2. Strip any directory components — pass only the base file name, never a full path.
  3. Ensure the extension is lowercase '.json' and the first character is alphanumeric.
  4. 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

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


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/c1d2b9cb778d31ab. Report an issue: GitHub.