{"record":{"id":"dcf3cfc81edc1900","repo":"different-ai/openwork","slug":"the-hostname-does-not-resolve","errorCode":null,"errorMessage":"the hostname does not resolve","messagePattern":"the hostname does not resolve","errorType":"exception","errorClass":"LocalManagedMcpPrivateUrlError","httpStatus":null,"severity":"error","filePath":"apps/server/src/local-managed-mcp-url-guard.ts","lineNumber":127,"sourceCode":"    throw new LocalManagedMcpPrivateUrlError(rawUrl, `protocol \"${url.protocol}\" is not allowed`);\n  }\n  if (url.username || url.password) {\n    throw new LocalManagedMcpPrivateUrlError(rawUrl, \"embedded URL credentials are not allowed\");\n  }\n  return url;\n}\n\nfunction allowPrivateUrls(): boolean {\n  return process.env.OPENWORK_DEV_MODE === \"1\" || process.env.OPENWORK_ALLOW_PRIVATE_MCP_URLS === \"1\";\n}\n\ntype ResolveAddresses = (hostname: string, options: LookupAllOptions) => Promise<LookupAddress[]>;\n\nconst resolveAddresses: ResolveAddresses = (hostname, options) => lookup(hostname, options);\n\nfunction validateResolvedAddresses(hostname: string, addresses: LookupAddress[]): void {\n  if (addresses.length === 0) {\n    throw new LocalManagedMcpPrivateUrlError(`https://${hostname}/`, \"the hostname does not resolve\");\n  }\n  if (allowPrivateUrls()) return;\n  for (const { address } of addresses) {\n    if (isLocalManagedMcpPrivateAddress(address)) {\n      throw new LocalManagedMcpPrivateUrlError(\n        `https://${hostname}/`,\n        `the hostname resolves to a private or reserved address (${address})`,\n      );\n    }\n  }\n}\n\n/**\n * Resolves and validates the address inside the socket connector's lookup\n * callback. The exact validated answer is handed to net.connect, so a later\n * DNS answer cannot replace it between validation and connection.\n */\nexport function createLocalManagedMcpPublicLookup(","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/local-managed-mcp-url-guard.ts#L109-L145","documentation":"LocalManagedMcpPrivateUrlError thrown by validateResolvedAddresses when DNS lookup of the MCP hostname returns zero addresses. The guard resolves the hostname (via lookup with LookupAllOptions) before allowing the URL; an unresolvable hostname means the server cannot be reached and may also indicate a typo or a dangling internal DNS name.","triggerScenarios":"assertLocalManagedMcpUrl (or the public lookup) calls validateResolvedAddresses with an empty array from lookup(hostname) — NXDOMAIN/servfail, or the host only has records the resolver can't see (e.g. internal-only DNS).","commonSituations":"Hostname typo in config; referencing a machine-local name (mybox.local, internal corp DNS) from a resolver that can't see it; DNS outage; the service was decommissioned.","solutions":["Fix the hostname spelling in the MCP server config","Test resolution on the same host: `nslookup <hostname>` or `dig <hostname>` — fix /etc/resolv.conf or DNS records if failing","If it's an internal-only name, ensure the app runs on a network/DNS that can resolve it","Use an IP or a publicly resolvable hostname if internal DNS cannot be fixed","Verify the MCP server host is still up and its DNS record exists"],"exampleFix":"// before\n{ \"url\": \"https://mcp.internal.corp/sse\" }   // dig: NXDOMAIN\n// after\n{ \"url\": \"https://mcp.example.com/sse\" }      // publicly resolvable","handlingStrategy":"validation","validationCode":"import { lookup } from \"node:dns/promises\";\nasync function resolves(hostname: string): Promise<boolean> {\n  try { return (await lookup(hostname, { all: true })).length > 0; } catch { return false; }\n}\n// await resolves(new URL(cfg.url).hostname) before registering","typeGuard":null,"tryCatchPattern":"try {\n  await mcp.addServer({ url });\n} catch (e) {\n  if (e instanceof LocalManagedMcpPrivateUrlError && e.message.includes(\"does not resolve\")) {\n    // check hostname spelling / DNS / network, then retry\n  } else throw e;\n}","preventionTips":["Run `dig`/`nslookup` on the target host before configuring it","Avoid machine-local hostnames (.local, corp-only names) unless the app's resolver sees them","Pin to public DNS-resolvable hostnames for shared configs"],"tags":["dns","network","mcp","config"],"backgroundTag":"dns-resolution-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}