NousResearch/hermes-agent · error · Error

Invalid profile name: ${value}

Error message

Invalid profile name: ${value}

What it means

Thrown by writeActiveDesktopProfile when the profile name being persisted is non-empty, not the literal 'default', and fails PROFILE_NAME_RE — the validation regex governing profile names. The value is trimmed first, so the check runs on the effective string that would be written to DESKTOP_PROFILE_CONFIG_PATH.

Source

Thrown at apps/desktop/electron/main.ts:6915

    const raw = fs.readFileSync(DESKTOP_PROFILE_CONFIG_PATH, 'utf8')
    const parsed = JSON.parse(raw)
    const name = parsed && typeof parsed.profile === 'string' ? parsed.profile.trim() : ''

    if (name && (name === 'default' || PROFILE_NAME_RE.test(name))) {
      return name
    }
  } catch {
    // Missing or malformed → no preference.
  }

  return null
}

function writeActiveDesktopProfile(name) {
  const value = typeof name === 'string' ? name.trim() : ''

  if (value && value !== 'default' && !PROFILE_NAME_RE.test(value)) {
    throw new Error(`Invalid profile name: ${value}`)
  }

  fs.mkdirSync(path.dirname(DESKTOP_PROFILE_CONFIG_PATH), { recursive: true })
  writeFileAtomic(DESKTOP_PROFILE_CONFIG_PATH, JSON.stringify({ profile: value || null }, null, 2))

  return value || null
}

// Sanitize a connection config into the renderer-facing shape. With no
// `profile` this describes the global/default connection (the existing
// behavior); with a `profile` it describes that profile's per-profile remote
// override (or an empty "local/inherit" view when the profile has none).
async function sanitizeDesktopConnectionConfig(config = readDesktopConnectionConfig(), profile = null) {
  const key = connectionScopeKey(profile)
  const scoped = key ? config.profiles?.[key] || null : null
  const block = key ? scoped || {} : config.remote || {}

  const envOverride = key ? false : Boolean(process.env.HERMES_DESKTOP_REMOTE_URL)

View on GitHub (pinned to c896c09c42)

Solutions

  1. Use a profile name matching PROFILE_NAME_RE (typically lowercase alphanumerics, '-', '_').
  2. Trim whitespace before passing the name — the code trims for the test, but keep inputs clean at the source.
  3. Reserve 'default' for the default profile; pick a distinct name otherwise.

Example fix

// before
writeActiveDesktopProfile('my profile!')

// after
const PROFILE_NAME_SAFE = /^[a-z0-9][a-z0-9_-]*$/i
const name = 'my profile!'
if (!PROFILE_NAME_SAFE.test(name)) throw new Error(`Invalid profile name: ${name}`)
writeActiveDesktopProfile(name)
Defensive patterns

Strategy: validation

Validate before calling

const PROFILE_NAME_SAFE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/ // mirror PROFILE_NAME_RE
function isValidProfileName(name) {
  const v = typeof name === 'string' ? name.trim() : ''
  return v === '' || v === 'default' || PROFILE_NAME_SAFE.test(v)
}

Type guard

function isWritableProfileName(name) {
  const v = String(name || '').trim()
  return v === '' || v === 'default' || PROFILE_NAME_SAFE.test(v)
}

Prevention

When it happens

Trigger: Setting the active desktop profile to a name containing characters outside PROFILE_NAME_RE (spaces, dots, slashes, unicode, etc. depending on the regex); passing 'default' is allowed only as the literal — any other reserved-looking name must match the regex.

Common situations: Programmatically writing a profile name sourced from user input or another config without sanitizing; renaming a profile to include characters the desktop forbids.

Related errors


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