{"record":{"id":"47d6a1e701f9caed","repo":"NousResearch/hermes-agent","slug":"unsupported-hermes-backend-url-protocol-protoco","errorCode":null,"errorMessage":"Unsupported Hermes backend URL protocol: ${protocol}","messagePattern":"Unsupported Hermes backend URL protocol: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/dashboard-token.ts","lineNumber":16,"sourceCode":"/**\n * Helpers for local dashboard session-token discovery.\n *\n * The desktop main process can pass HERMES_DASHBOARD_SESSION_TOKEN when it\n * spawns the local dashboard, but the dashboard is the source of truth for the\n * token it actually serves to the renderer. If those drift, HTTP readiness\n * probes still pass while /api/ws rejects the renderer's token.\n */\n\nconst DEFAULT_TOKEN_FETCH_TIMEOUT_MS = 3_000\n\nasync function fetchPublicText(url, options: any = {}) {\n  const { protocol } = new URL(url)\n\n  if (protocol !== 'http:' && protocol !== 'https:') {\n    throw new Error(`Unsupported Hermes backend URL protocol: ${protocol}`)\n  }\n\n  const timeoutMs = options.timeoutMs ?? DEFAULT_TOKEN_FETCH_TIMEOUT_MS\n\n  const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }).catch(error => {\n    if (error.name === 'TimeoutError') {\n      throw new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`)\n    }\n\n    throw error\n  })\n\n  const text = await res.text()\n\n  if (!res.ok) {\n    throw new Error(`${res.status}: ${text || res.statusText}`)\n  }\n","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/electron/dashboard-token.ts#L1-L34","documentation":"ValueError from _validate_execution_mode (cron/jobs.py:1563): no_agent=True was set but no script was supplied. A no_agent job's entire body is the script — with neither an agent turn nor a script there is literally nothing to execute. Shared by create_job and update_job, so later updates can't create an empty no_agent job either.","triggerScenarios":"create_job(prompt=..., no_agent=True) with no script=; or update_job(id, {'no_agent': True}) on a job whose script is None/empty.","commonSituations":"Copy-pasting a job template and deleting the script line; assuming the prompt still runs without an agent (it doesn't); enabling no_agent as a 'cost saving' without providing the replacement workload.","solutions":["Supply a script when using no_agent: create_job(..., no_agent=True, script='./collect.sh').","If you want the model to run, just omit no_agent (default False) and keep the prompt.","When updating, include both {'no_agent': True, 'script': ...} in the same call."],"exampleFix":"# before\ncreate_job(prompt=\"gather data\", schedule=\"1h\", no_agent=True)\n\n# after\ncreate_job(prompt=\"gather data\", schedule=\"1h\", no_agent=True, script=\"python gather.py > out.json\")","handlingStrategy":"validation","validationCode":"def valid_no_agent(no_agent: bool, script) -> bool:\n    return (not no_agent) or bool(script)  # no_agent demands a script body","typeGuard":null,"tryCatchPattern":"try:\n    create_job(..., no_agent=True)\nexcept ValueError as e:\n    if \"requires a script\" in str(e):\n        create_job(..., no_agent=True, script=\"./run.sh\")\n        raise","preventionTips":["Treat no_agent + script as an atomic pair — always set them together.","Remember the prompt does NOT run in no_agent mode; only the script executes."],"tags":["cron","no-agent","script","validation"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}