{"record":{"id":"69908f2af503c4b4","repo":"tursodatabase/turso","slug":"overwriting-the-host-header-is-not-supported","errorCode":null,"errorMessage":"overwriting the 'Host' header is not supported","messagePattern":"overwriting the 'Host' header is not supported","errorType":"exception","errorClass":"DatabaseError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/protocol.ts","lineNumber":243,"sourceCode":"   */\n  requestHeaders?: Record<string, string>;\n}\n\nfunction buildHeaders(ctx: HttpContext): Record<string, string> {\n  const headers: Record<string, string> = {\n    'Content-Type': 'application/json',\n  };\n  if (ctx.authToken) {\n    headers['Authorization'] = `Bearer ${ctx.authToken}`;\n  }\n  if (ctx.remoteEncryptionKey) {\n    headers[ENCRYPTION_KEY_HEADER] = ctx.remoteEncryptionKey;\n  }\n  for (const [name, value] of Object.entries(ctx.requestHeaders ?? {})) {\n    // `Host` is a forbidden fetch header and would be silently dropped —\n    // throw instead so the caller learns the override never takes effect.\n    if (name.toLowerCase() === 'host') {\n      throw new DatabaseError(\"overwriting the 'Host' header is not supported\");\n    }\n    headers[name] = value;\n  }\n  return headers;\n}\n\nfunction buildFetchOptions(ctx: HttpContext, body: string, signal?: AbortSignal): RequestInit {\n  return {\n    method: 'POST',\n    headers: buildHeaders(ctx),\n    body,\n    signal,\n  };\n}\n\n/** Per-query options. Override the session-level defaults for a single call. */\nexport interface QueryOptions {\n  /** Per-query timeout in milliseconds. Overrides defaultQueryTimeout for this call. */","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/protocol.ts#L225-L261","documentation":"DatabaseError thrown while building request headers when a per-query requestHeaders object (QueryOptions.requestHeaders) contains a Host key, matched case-insensitively. fetch() classifies Host as a forbidden header and would silently drop the override, so the driver throws to make the no-op visible instead of letting routing logic quietly not work.","triggerScenarios":"Passing { requestHeaders: { Host: 'db.example.com' } } as queryOptions to run/get/all/exec/batch/pragma or statement methods; spreading an incoming request's full header set (which includes host) into queryOptions; case variants 'host'/'HOST' which are rejected the same way.","commonSituations":"Proxy or multi-tenant routing setups that try to select a backend via the Host header; middleware that forwards original client headers to the database request; header constants shared across services that include host.","solutions":["Route by changing the connection's url (connect({ url })), never by overriding Host","Strip the Host key before passing headers: filter out keys whose lowercase name is 'host'","Use custom x-* headers for routing metadata — those pass through fine"],"exampleFix":"// before\nawait db.all(sql, { requestHeaders: { ...incomingHeaders } }); // incomingHeaders contains Host\n\n// after\nconst headers = Object.fromEntries(\n  Object.entries(incomingHeaders).filter(([k]) => k.toLowerCase() !== \"host\"),\n);\nawait db.all(sql, { requestHeaders: headers });","handlingStrategy":"validation","validationCode":"const stripHost = (h: Record<string, string> = {}): Record<string, string> =>\n  Object.fromEntries(\n    Object.entries(h).filter(([k]) => k.toLowerCase() !== \"host\"),\n  );\n\nawait db.all(sql, { requestHeaders: stripHost(incomingHeaders) });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Route by the connection url, never by the Host header — fetch forbids it","Whitelist header keys when forwarding; never spread a full incoming header set into queryOptions","Prefer x-* custom headers for routing metadata"],"tags":["http-headers","fetch","configuration","javascript"],"backgroundTag":"forbidden-http-header","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}