NousResearch/hermes-agent · error

Theme file is not a JSON object.

Error message

Theme file is not a JSON object.

What it means

Thrown by parseVscodeTheme when the theme file text, after stripping comments and trailing commas, parses to a non-object (or null) — i.e. JSON.parse succeeded but the top level is a number, string, array, or empty. The parser intentionally tolerates JSONC (comments, trailing commas) but still requires a top-level object.

Source

Thrown at apps/desktop/src/themes/vscode.ts:83

/**
 * Parse a VS Code theme file. These ship as JSONC (line/block comments and
 * trailing commas), so a plain `JSON.parse` rejects most real-world files.
 * Strips comments + trailing commas, then parses. Throws on hard syntax errors.
 */
export function parseVscodeTheme(text: string): VscodeColorTheme {
  const stripped = text
    // Block comments.
    .replace(/\/\*[\s\S]*?\*\//g, '')
    // Line comments (not inside strings — naive but fine for theme files).
    .replace(/(^|[^:"'\\])\/\/[^\n\r]*/g, '$1')
    // Trailing commas before } or ].
    .replace(/,(\s*[}\]])/g, '$1')

  const parsed: unknown = JSON.parse(stripped)

  if (!parsed || typeof parsed !== 'object') {
    throw new Error('Theme file is not a JSON object.')
  }

  return parsed as VscodeColorTheme
}

const isDarkType = (raw: VscodeColorTheme, background: string): boolean => {
  const type = (raw.type ?? '').toLowerCase()

  if (type.includes('light')) {
    return false
  }

  if (type === 'dark' || type === 'hc' || type === 'hc-black' || type.includes('dark')) {
    return true
  }

  // No usable `type` — bucket by background luminance.
  return luminance(background) < 0.4

View on GitHub (pinned to c896c09c42)

Solutions

  1. Confirm the file is a VS Code color theme (JSON object with a 'colors' map), not a token array or manifest.
  2. If the file contains '//' inside string values (URLs), escape or quote them so the naive comment-stripping does not corrupt the JSON.
  3. Validate the raw file with a JSONC-aware linter before import.
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeThemeObject(text: string): boolean {
  try {
    // reuse same stripping rules minimally: must start with '{'
    return text.trimStart().startsWith('{')
  } catch { return false }
}

Type guard

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

Try / catch

try {
  parseVscodeTheme(text)
} catch (e) {
  if (e instanceof Error && e.message === 'Theme file is not a JSON object.')
    rejectFile('Expected a JSON object theme file')
  else if (e instanceof SyntaxError) rejectFile('Theme file is not valid JSON/JSONC')
  else throw e
}

Prevention

When it happens

Trigger: Feeding a .json theme file that is actually an array (token arrays like some semantic-token themes), an empty file, a plain string, or a file whose comment-stripping regex mangled the content into a non-object.

Common situations: Pointing the importer at a semantic token or icon manifest instead of a color theme file; a theme file containing URLs with '//' that the naive line-comment regex truncated, leaving invalid JSON remnants.

Related errors


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