walkor/workerman · error · RuntimeException
Request->setSidCookie() fail, header already send
Error message
Request->setSidCookie() fail, header already send
What it means
setSidCookie() writes the Set-Cookie header onto $this->connection->headers. When the Request no longer has a connection (headers already sent or the request object was detached for reuse in a background context) there is nowhere to put the cookie, so Workerman throws.
Source
Thrown at src/Protocols/Http/Request.php:738
public static function createSessionId(): string
{
$sid = session_create_id();
if ($sid === false) {
throw new RuntimeException('session_create_id() failed');
}
return $sid;
}
/**
* @param string $sessionName
* @param string $sid
* @param array $cookieParams
* @return void
*/
protected function setSidCookie(string $sessionName, string $sid, array $cookieParams): void
{
if (!$this->connection) {
throw new RuntimeException('Request->setSidCookie() fail, header already send');
}
$this->connection->headers['Set-Cookie'] = [$sessionName . '=' . $sid
. (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain'])
. (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime'])
. (empty($cookieParams['path']) ? '' : '; Path=' . $cookieParams['path'])
. (empty($cookieParams['samesite']) ? '' : '; SameSite=' . $cookieParams['samesite'])
. (!$cookieParams['secure'] ? '' : '; Secure')
. (!$cookieParams['httponly'] ? '' : '; HttpOnly')];
}
/**
* __toString.
*/
public function __toString(): string
{
return $this->buffer;
}
View on GitHub (pinned to 1391112a61)
Solutions
- Touch the session (and any setSidCookie-triggering call) before sending the response
- Pass the session id string to background jobs instead of the whole Request object
- Verify client sends a valid session cookie on subsequent requests so no new cookie must be emitted
Example fix
// before $connection->send(new Response(200, [], 'ok')); $request->sessionId($newId); // needs Set-Cookie -> throws // after $request->sessionId($newId); $connection->send(new Response(200, [], 'ok'));
Defensive patterns
Strategy: type-guard
Type guard
function canSendCookie(Workerman\Protocols\Http\Request $request): bool
{
return $request->connection !== null;
} Prevention
- Do all session-id/cookie work before the first send() on the connection
- Treat Request as single-request-scoped; never reuse it across ticks, processes, or jobs
When it happens
Trigger: The session-id path reaching setSidCookie() on a Request whose connection property is null: response already sent before session()/sessionId() ran, or the Request was captured and processed later (Timer/queue) after the HTTP exchange finished.
Common situations: Same lifecycle mistakes as the sibling 'Request->session() fail, header already send' error: early response send followed by session writes, or request objects handed to deferred jobs.
Related errors
- Request->session() fail, header already send
- session_create_id() failed
- Please install redis extension.
- Redis connect {$config['host']}:{$config['port']} fail.
- Bad remoteAddress
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/2293408f386e9c1e.
Report an issue: GitHub.