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
- Use a profile name matching PROFILE_NAME_RE (typically lowercase alphanumerics, '-', '_').
- Trim whitespace before passing the name — the code trims for the test, but keep inputs clean at the source.
- 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
- Restrict profile names to the safe alphabet at the input field
- Trim before persisting
- Treat 'default' as reserved
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
- SSH host is required.
- Branch name is required.
- Missing URL
- Invalid data URL
- Not a directory: ${watchDir}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/927c02bd78a98fe2.
Report an issue: GitHub.