Skip to content

Cookies drops same-name cookies set for a different domain or path #10469

Open

Description

@jpowersdev

What version of Effect is running?

4.1.2 (also main)

What steps can reproduce the bug?

import { Cookies, HttpClientRequest, HttpClientResponse } from "effect/http"

const headers = new Headers()
headers.append("set-cookie", "token=root; Path=/")
headers.append("set-cookie", "token=api; Path=/api")

const response = HttpClientResponse.fromWeb(
  HttpClientRequest.get("https://example.com/login"),
  new Response(null, { headers })
)

Cookies.toSetCookieHeaders(response.cookies)

What is the expected behavior?

["token=root; Path=/", "token=api; Path=/api"]. RFC 6265 §5.3 identifies a cookie by name, domain and path, and browsers keep both.

What do you see instead?

["token=api; Path=/api"]. Cookies is keyed by name, so a later cookie replaces an earlier one with the same name whatever its Domain or Path.

Additional information

  • HttpClient.withCookiesRef scopes its jar by name, domain and path since fix(http): send stored cookies only to the matching host #9614, but it is fed from response.cookies, so token=root is never stored and sent. A logout at www.example.com that clears session for both the host and Domain=example.com only deletes one of them.
  • On the server, HttpServerResponse.setCookie and expireCookie cannot set or expire one name for two scopes in the same response, and fromWeb drops them when proxying.
  • The only lossless workaround on the client is HttpClientResponse.toWeb on fetch-backed responses, which hands over the body. response.headers keeps one set-cookie value, either the last one or all of them joined with commas, which Expires dates make unsplittable.

#9614 listed this case as out of scope. I've opened two draft PRs with alternative fixes: #10470 keeps the name-based Cookies API and only stops parsing from dropping cookies (patch); #10471 identifies cookies by name, domain and path everywhere (breaking, minor).

Activity

  1. self-assigned this
    on Nov 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions