NousResearch/hermes-agent · error

Remote gateway URL must be http:// or https://, got ${parsed

Error message

Remote gateway URL must be http:// or https://, got ${parsed.protocol}

What it means

ValueError from _validate_execution_mode (cron/jobs.py:1557): a job combines monitor_script/monitor_url with no_agent=True. Monitor jobs exist to suppress or wake the agent based on source changes; no_agent=True removes the agent entirely, which would silently degrade the monitor into a plain script job. Enforced identically at create and update time.

Source

Thrown at apps/desktop/electron/connection-config.ts:78

  // 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(/\/+$/, '')

  return `${wsScheme}://${parsed.host}${prefix}/api/ws?token=${encodeURIComponent(token)}`
}

function buildGatewayWsUrlWithTicket(baseUrl, ticket) {

View on GitHub (pinned to c896c09c42)

Solutions

  1. If you don't need the agent, drop the monitor fields and use a plain no_agent script job.
  2. If you need change detection, keep monitor_script/monitor_url and leave no_agent unset/False.
  3. When updating, pass the full consistent mode — clear monitor fields AND set no_agent in one update if switching kinds.

Example fix

# before
create_job(prompt=..., schedule="10m", no_agent=True, monitor_script="uptime")

# after
create_job(prompt=..., schedule="10m", no_agent=True, script="uptime | tee /tmp/u.log")
Defensive patterns

Strategy: validation

Validate before calling

def compatible_mode(monitor_script, monitor_url, no_agent) -> bool:
    return not ((monitor_script or monitor_url) and no_agent)  # monitor implies agent

Try / catch

try:
    create_job(..., no_agent=True, monitor_url=u)
except ValueError as e:
    if "cannot be combined with no_agent" in str(e):
        create_job(..., no_agent=True, script=s)  # plain script job instead
        raise

Prevention

When it happens

Trigger: create_job(no_agent=True, monitor_url=...) or update_job(id, {'no_agent': True}) on an existing monitor job — flipping no_agent on later is exactly the 'update door' this shared validator closes.

Common situations: Trying to make a monitor job cheaper by removing the agent; retrofitting no_agent onto an existing monitor job to 'just run the check'; copying config between jobs of different kinds.

Related errors


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