{"record":{"id":"96b0a39de84abfc9","repo":"paperclipai/paperclip","slug":"enter-the-hermes-api-base-url","errorCode":null,"errorMessage":"Enter the Hermes API base URL.","messagePattern":"Enter the Hermes API base URL\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/src/components/new-agent/NewAgentSetup.tsx","lineNumber":396,"sourceCode":"      !/^https:\\/\\/github\\.com\\/[^/]+\\/[^/]+/.test(repository.trim())\n    )\n      throw new Error(\"Enter a GitHub repository URL.\");\n    if (\n      [\"cursor_cloud\", \"hermes_gateway\"].includes(adapterType) &&\n      !apiKey.trim() &&\n      !selectedBinding\n    )\n      throw new Error(\n        adapterType === \"cursor_cloud\"\n          ? \"Enter a Cursor API key.\"\n          : `Enter ${envKey} or select an organization secret.`,\n      );\n    if (adapterType === \"hermes_gateway\") {\n      try {\n        const url = new URL(gatewayUrl.trim());\n        if (![\"https:\", \"http:\"].includes(url.protocol)) throw new Error();\n      } catch {\n        throw new Error(\"Enter the Hermes API base URL.\");\n      }\n    }\n    if (usingKimiApi && !kimiModel.trim())\n      throw new Error(\"Enter the Kimi API model name.\");\n    return buildConfig(nextConnection);\n  }\n  function pendingCredentials(nextConnection = connection) {\n    return {\n      ...nextConnection?.credentials,\n      ...(hasCredentialField && apiKey.trim()\n        ? { [envKey]: apiKey.trim() }\n        : {}),\n    };\n  }\n\n  async function runTest(nextConnection = connection): Promise<boolean> {\n    if (!ready) return false;\n    const run = ++generation.current;","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/ui/src/components/new-agent/NewAgentSetup.tsx#L378-L414","documentation":"For the hermes_gateway adapter type, preparedConfig() parses the gateway URL with new URL() and requires an http: or https: protocol. If the trimmed gatewayUrl is empty, malformed, or uses another scheme, the parse/validation throws internally and the catch re-throws \"Enter the Hermes API base URL.\" as the user-facing validation error.","triggerScenarios":"Submitting setup with adapterType \"hermes_gateway\" and gatewayUrl empty, \"localhost:8080\" (no scheme), \"ftp://...\", or any string that new URL() cannot parse.","commonSituations":"Leaving the Hermes gateway field blank; entering a host without https://; pasting a URL with a typo or trailing invalid characters; using a non-HTTP scheme.","solutions":["Enter the full gateway base URL including the scheme, e.g. https://hermes.example.com.","Prepend https:// if you entered a bare hostname.","Use only http: or https: schemes — other protocols are rejected.","Verify no stray whitespace/characters break URL parsing."],"exampleFix":"// before\ngatewayUrl: \"hermes.internal:8443\"\n\n// after\ngatewayUrl: \"https://hermes.internal:8443\"","handlingStrategy":"validation","validationCode":"let gatewayOk = false;\ntry {\n  const u = new URL(gatewayUrl.trim());\n  gatewayOk = [\"https:\", \"http:\"].includes(u.protocol);\n} catch { gatewayOk = false; }\nif (adapterType === \"hermes_gateway\" && !gatewayOk)\n  showError(\"Enter the Hermes API base URL.\");","typeGuard":"const isValidHttpUrl = (s: string): boolean => {\n  try {\n    return [\"https:\", \"http:\"].includes(new URL(s.trim()).protocol);\n  } catch { return false; }\n};","tryCatchPattern":"try {\n  const cfg = preparedConfig();\n  submit(cfg);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"Hermes API base URL\")) {\n    setGatewayFieldError(\"Use a full http(s) URL, e.g. https://hermes.example.com\");\n  } else throw e;\n}","preventionTips":["Always include the https:// (or http://) scheme in gateway URLs.","Validate with new URL() in the form before submit.","Normalize bare hostnames by prefixing the scheme on paste."],"tags":["validation","form","url","hermes-gateway"],"backgroundTag":"invalid-url-format","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}