NousResearch/hermes-agent · error
Remote gateway URL is not valid: ${error.message}
Error message
Remote gateway URL is not valid: ${error.message} What it means
ValueError from _validate_execution_mode (cron/jobs.py:1552), the single shared validator called by BOTH create_job and update_job: a job was given both monitor_script and monitor_url. A monitor job watches exactly one source for changes (to suppress or wake the agent), so two sources are ambiguous and rejected up front — the update door cannot reintroduce the violation either.
Source
Thrown at apps/desktop/electron/connection-config.ts:74
throw new Error('Remote gateway URL is required.')
}
// Users routinely paste scheme-less "host:port" (a Tailscale IP, a LAN
// hostname). Without this, `new URL('100.64.0.1:9119')` either throws or —
// worse — parses `host:` as the protocol and produces a baffling
// "must be http:// or https://, got myhost:" error. Only a real
// `scheme://` prefix opts out, so explicit non-http schemes (ftp://,
// file://) still reach the protocol check below and get rejected.
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(value)) {
value = `http://${value}`
}
let parsed
try {
parsed = new URL(value)
} catch (error) {
throw new Error(`Remote gateway URL is not valid: ${error.message}`)
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
throw new Error(`Remote gateway URL must be http:// or https://, got ${parsed.protocol}`)
}
parsed.hash = ''
parsed.search = ''
parsed.pathname = parsed.pathname.replace(/\/+$/, '')
return parsed.toString().replace(/\/+$/, '')
}
function buildGatewayWsUrl(baseUrl, token) {
const parsed = new URL(baseUrl)
const wsScheme = parsed.protocol === 'https:' ? 'wss' : 'ws'
const prefix = parsed.pathname.replace(/\/+$/, '')
View on GitHub (pinned to c896c09c42)
Solutions
- Keep exactly one monitor source: pass only monitor_script or only monitor_url.
- To switch sources, first update the job setting the old field to None, then set the new one.
- If you truly need two sources, create two separate monitor jobs.
Example fix
# before create_job(prompt=..., schedule="5m", monitor_script="curl -s x", monitor_url="https://x") # after create_job(prompt=..., schedule="5m", monitor_url="https://x") # script removed
Defensive patterns
Strategy: validation
Validate before calling
def valid_monitor_args(monitor_script, monitor_url) -> bool:
return not (bool(monitor_script) and bool(monitor_url)) # at most one source Try / catch
try:
create_job(..., monitor_script=ms, monitor_url=mu)
except ValueError as e:
if "mutually exclusive" in str(e):
create_job(..., monitor_url=mu) # keep exactly one source, drop the other
raise Prevention
- One monitor source per job — model 'switch source' as clear-old-then-set-new in a single update.
- When merging job configs, assert at most one monitor_* key is present.
When it happens
Trigger: create_job(monitor_script='...', monitor_url='...') or update_job(id, {monitor_script: '...'}) on a job that already has monitor_url set (or vice versa).
Common situations: Iteratively building a monitor job and adding a URL after starting with a script; merging two job configs programmatically; an LLM 'upgrading' a script monitor to a URL monitor without clearing the old field.
Related errors
- Preview mode — launching is disabled.
- no install root
- Remote gateway URL must be http:// or https://, got ${parsed
- Desktop installation ID is invalid.
- Unknown uninstall mode: ${mode}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/33725f6661c5dd8c.
Report an issue: GitHub.