{"record":{"id":"fb8b44a6a51291ee","repo":"tursodatabase/turso","slug":"empty-request","errorCode":null,"errorMessage":"Empty request","messagePattern":"Empty request","errorType":"console","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"cli/sync_server.rs","lineNumber":1290,"sourceCode":"fn parse_content_length(headers: &str) -> Option<usize> {\n    for line in headers.lines() {\n        let lower = line.to_lowercase();\n        if lower.starts_with(\"content-length:\") {\n            let value = line.split(':').nth(1)?.trim();\n            return value.parse().ok();\n        }\n    }\n    None\n}\n\nfn parse_http_request(data: &[u8]) -> Result<(String, String, Vec<u8>)> {\n    let header_end = find_header_end(data, 0).ok_or_else(|| anyhow!(\"Invalid HTTP request\"))?;\n    let headers = String::from_utf8_lossy(&data[..header_end]);\n\n    let first_line = headers\n        .lines()\n        .next()\n        .ok_or_else(|| anyhow!(\"Empty request\"))?;\n    let parts: Vec<&str> = first_line.split_whitespace().collect();\n\n    if parts.len() < 2 {\n        return Err(anyhow!(\"Invalid request line\"));\n    }\n\n    let method = parts[0].to_string();\n    let path = parts[1].to_string();\n    let body = data[header_end + 4..].to_vec();\n\n    Ok((method, path, body))\n}\n\nfn text_response(status: u16, body: &str) -> HttpResponse {\n    HttpResponse {\n        status,\n        content_type: \"text/plain\".to_string(),\n        body: body.as_bytes().to_vec(),","sourceCodeStart":1272,"sourceCodeEnd":1308,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/cli/sync_server.rs#L1272-L1308","documentation":"After the \\r\\n\\r\\n terminator is found, parse_http_request takes the first line of the header block as the request line. This error fires when the header block is empty - i.e. the request bytes begin immediately with \\r\\n\\r\\n, so headers.lines().next() yields None. It is distinct from 778: framing was found, but there is no request line in front of it.","triggerScenarios":"A client sends leading blank lines before the request (bytes start with \\r\\n\\r\\n followed by the real request), or sends only a terminator with nothing before it; find_header_end returns 0 and the header slice is empty.","commonSituations":"Telnet sessions pressing Enter before typing the request; sloppy pipelining that leaves trailing blank lines from the previous response cycle; scripts concatenating request fragments incorrectly.","solutions":["Start the request bytes directly with the request line: 'POST /v2/pipeline HTTP/1.1\\r\\n...'","Strip stray leading CRLFs client-side before writing to the socket","When embedding, map this to a 400 Bad Request response"],"exampleFix":"// before: stray leading blank lines\nstream.write_all(b\"\\r\\n\\r\\nPOST /v2/pipeline HTTP/1.1\\r\\n\\r\\n\")?;\n\n// after: request line first, single terminator\nstream.write_all(b\"POST /v2/pipeline HTTP/1.1\\r\\nContent-Length: 0\\r\\n\\r\\n\")?;","handlingStrategy":"validation","validationCode":"// Client-side: request must start with the request line, not a blank line.\nfn request_starts_with_request_line(raw: &[u8]) -> bool {\n    !raw.starts_with(b\"\\r\\n\") && !raw.starts_with(b\"\\n\")\n}","typeGuard":null,"tryCatchPattern":"let (method, path, body) = match parse_http_request(&request_data) {\n    Ok(parsed) => parsed,\n    Err(err) if err.to_string() == \"Empty request\" => {\n        respond_400(&mut stream)?; // leading blank lines: malformed request\n        return Ok(());\n    }\n    Err(err) => return Err(err),\n};","preventionTips":["Write the request line as the very first bytes on the socket","In test scripts, strip stray newlines from templated request strings","Treat empty-first-line requests as client bugs: fix the sender, not the server"],"tags":["http","sync-server","request-parsing","empty-request"],"backgroundTag":"malformed-http-request","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}