NousResearch/hermes-agent · error · Error

Expected exported session JSON or JSONL

Error message

Expected exported session JSON or JSONL

What it means

normalizeImportSessions accepts (a) an array of session objects, (b) a single session object, or (c) a {sessions: [...]} export wrapper, and filters to plain objects. If any candidate item is null, a primitive, or an array, the counts diverge and this error is thrown — the file is neither a Hermes session export nor JSONL of session objects.

Source

Thrown at web/src/lib/session-import.ts:21

export type ImportableSession = Record<string, unknown>;

function normalizeImportSessions(value: unknown): ImportableSession[] {
  const candidate =
    value &&
    typeof value === "object" &&
    !Array.isArray(value) &&
    Array.isArray((value as { sessions?: unknown }).sessions)
      ? (value as { sessions: unknown[] }).sessions
      : Array.isArray(value)
        ? value
        : [value];

  const sessions = candidate.filter(
    (item): item is ImportableSession =>
      !!item && typeof item === "object" && !Array.isArray(item),
  );
  if (sessions.length !== candidate.length) {
    throw new Error("Expected exported session JSON or JSONL");
  }
  return sessions;
}

export function parseImportSessions(text: string): ImportableSession[] {
  const trimmed = text.trim();
  if (!trimmed) throw new Error("File is empty");

  try {
    return normalizeImportSessions(JSON.parse(trimmed));
  } catch (jsonError) {
    const lines = trimmed.split(/\r?\n/).filter((line) => line.trim());
    if (lines.length <= 1) throw jsonError;
    return normalizeImportSessions(lines.map((line) => JSON.parse(line)));
  }
}

export function importSummary(result: SessionImportResponse): string {

View on GitHub (pinned to c896c09c42)

Solutions

  1. Re-export sessions from the source dashboard/hermes instance and import that file unmodified.
  2. Inspect the file: every element (or JSONL line) must be a JSON object representing one session.
  3. If migrating from another tool, write a converter that emits an array of session objects (or {sessions: [...]}) first.

Example fix

// before
[{ "id": "s1" }, "not-a-session"]

// after
[{ "id": "s1" }, { "id": "s2" }]
Defensive patterns

Strategy: type-guard

Validate before calling

const looksLikeSessionExport = (v: unknown): boolean => {
  const items = Array.isArray(v)
    ? v
    : typeof v === 'object' && v !== null && Array.isArray((v as { sessions?: unknown }).sessions)
      ? (v as { sessions: unknown[] }).sessions
      : [v]
  return items.length > 0 && items.every(i => !!i && typeof i === 'object' && !Array.isArray(i))
}
if (!looksLikeSessionExport(parsed)) { rejectFile('Not a Hermes session export'); return }

Type guard

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}

Try / catch

try {
  const sessions = parseImportSessions(text)
} catch (err) {
  if (String(err) === 'Expected exported session JSON or JSONL') {
    showError('File must contain session objects (JSON array, {sessions:[...]}, or JSONL)')
    return
  }
  throw err
}

Prevention

When it happens

Trigger: Importing a JSON file whose top-level array mixes session objects with strings/numbers; a wrapped export where sessions contains nulls; JSONL lines that parse to scalars; pasting an arbitrary API response into the import box.

Common situations: Hand-editing an export and corrupting entries; importing the wrong file (config dump, log file); exports from a different tool with a similar but incompatible shape.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/dc3263ce6bc02436. Report an issue: GitHub.