NousResearch/hermes-agent · error

${res.status}: ${text || res.statusText}

Error message

${res.status}: ${text || res.statusText}

What it means

AmbiguousJobReference (a LookupError subclass, cron/jobs.py:1804) raised by resolve_job_ref when a name reference matches the stored ID of nothing but the lowercased names of two or more jobs. Since pause/resume/update accept either an ID or a name, a duplicated name cannot be acted on safely; the message lists the matching job IDs so you can disambiguate.

Source

Thrown at apps/desktop/electron/dashboard-token.ts:32

  if (protocol !== 'http:' && protocol !== 'https:') {
    throw new Error(`Unsupported Hermes backend URL protocol: ${protocol}`)
  }

  const timeoutMs = options.timeoutMs ?? DEFAULT_TOKEN_FETCH_TIMEOUT_MS

  const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }).catch(error => {
    if (error.name === 'TimeoutError') {
      throw new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`)
    }

    throw error
  })

  const text = await res.text()

  if (!res.ok) {
    throw new Error(`${res.status}: ${text || res.statusText}`)
  }

  return text
}

function extractInjectedDashboardToken(html) {
  const match = /window\.__HERMES_SESSION_TOKEN__\s*=\s*("(?:\\.|[^"\\])*")/.exec(String(html || ''))

  if (!match) {
    return null
  }

  try {
    return JSON.parse(match[1])
  } catch {
    return null
  }
}

View on GitHub (pinned to c896c09c42)

Solutions

  1. Use one of the job IDs listed in the error message instead of the name.
  2. Find IDs with `hermes cron list`.
  3. Rename or remove the duplicate jobs so names are unique again.
  4. Catch AmbiguousJobReference specifically when scripting name-based lookups.

Example fix

# before
resume_job("daily-digest")  # two jobs share this name

# after
resume_job("a1b2c3d4")  # ID taken from the error message / `hermes cron list`
Defensive patterns

Strategy: try-catch

Validate before calling

from cron.jobs import load_jobs

def unique_name(name: str) -> bool:
    n = name.lower()
    return sum(1 for j in load_jobs() if (j.get("name") or "").lower() == n) <= 1

Try / catch

from cron.jobs import AmbiguousJobReference, resume_job
try:
    resume_job(ref)
except AmbiguousJobReference as e:
    # message lists the matching IDs — pick one explicitly
    job_id = parse_ids_from_error(e) or choose_via_list_jobs()
    resume_job(job_id)

Prevention

When it happens

Trigger: Two jobs created with the same name (names are not unique), then resume_job('daily-digest'), pause_job('daily-digest'), or any name-based lookup/CLI verb targeting that name.

Common situations: Re-running a setup script or `hermes cron add` that recreates the same-named job; an agent creating a job per day with a fixed name; case-only name collisions resolved via .lower() matching.

Related errors


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