{"id":"6415e47c58cd8d43","repo":"curl/curl","slug":"error-starting-frame-d","errorCode":null,"errorMessage":"error starting frame: %d\n","messagePattern":"error starting frame: (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"docs/examples/websocket-updown.c","lineNumber":72,"sourceCode":"  char buf[1024];\n  size_t blen;\n  size_t nsent;\n};\n\nstatic size_t read_cb(char *buf, size_t nitems, size_t buflen, void *p)\n{\n  struct read_ctx *ctx = p;\n  size_t len = nitems * buflen;\n  size_t left = ctx->blen - ctx->nsent;\n\n  if(!ctx->nsent) {\n    CURLcode result;\n    /* On first call, set the FRAME information to be used (it defaults to\n     * CURLWS_BINARY otherwise). */\n    result = curl_ws_start_frame(ctx->curl, CURLWS_TEXT,\n                                 (curl_off_t)ctx->blen);\n    if(result != CURLE_OK) {\n      fprintf(stderr, \"error starting frame: %d\\n\", (int)result);\n      return CURL_READFUNC_ABORT;\n    }\n  }\n  fprintf(stderr, \"read(len=%d, left=%d)\\n\", (int)len, (int)left);\n  if(left) {\n    if(left < len)\n      len = left;\n    memcpy(buf, ctx->buf + ctx->nsent, len);\n    ctx->nsent += len;\n    return len;\n  }\n  return 0;\n}\n\nint main(int argc, const char *argv[])\n{\n  CURL *curl;\n  struct read_ctx rctx;","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/curl/curl/blob/527573490eb2564b3d7c9dd51d8bff963b5d6303/docs/examples/websocket-updown.c#L54-L90","documentation":"Printed in the read callback of the websocket-updown example when curl_ws_start_frame() returns a non-CURLE_OK code on the callback's first invocation. curl_ws_start_frame() begins a new outbound WebSocket frame with the given flags (here CURLWS_TEXT) and payload length; failure means libcurl could not initiate the frame send on the current transfer. The callback then aborts the upload by returning CURL_READFUNC_ABORT.","triggerScenarios":"Called inside read_cb() at the first chunk when CURLOPT_UPLOAD is set on a WebSocket (ws/wss) transfer and curl_ws_start_frame(curl, CURLWS_TEXT, blen) fails. Happens when the easy handle is not actually in a WebSocket send state, the connection upgrade never completed, CURLOPT_CONNECT_ONLY was mis-set, or the frame length/flags are rejected.","commonSituations":"Pointing the example at a plain http:// URL instead of ws/wss, setting CURLOPT_UPLOAD without a valid WebSocket connection, a server that rejected the WebSocket upgrade (no 101), or using a libcurl build compiled without WebSocket support.","solutions":["Use a ws:// or wss:// URL and ensure the server completes the WebSocket upgrade (HTTP 101) before the read callback runs.","Verify the libcurl build supports WebSockets (curl --version shows 'WebSocket'); rebuild with --enable-websockets if missing.","Confirm CURLOPT_UPLOAD is paired with a real WS transfer and that curl_ws_start_frame flags (CURLWS_TEXT/CURLWS_BINARY) and length are valid.","Inspect the returned CURLcode int in the message against curl_easy_strerror() to identify the exact failure (e.g. CURLE_URL_MALFORMAT, CURLE_HTTP_RETURNED_ERROR)."],"exampleFix":"// before\ncurl_easy_setopt(curl, CURLOPT_URL, \"http://example.com\");\ncurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n// after\ncurl_easy_setopt(curl, CURLOPT_URL, \"wss://echo.websocket.events\");\ncurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);","handlingStrategy":"validation","validationCode":"static CURLcode ws_upload_preflight(CURL *curl, const char *url, size_t blen) {\n  if(curl == NULL)          return CURLE_BAD_FUNCTION_ARGUMENT;\n  if(blen == 0)             return CURLE_BAD_FUNCTION_ARGUMENT;\n  if(strncmp(url, \"ws://\", 5) && strncmp(url, \"wss://\", 6))\n                            return CURLE_UNSUPPORTED_PROTOCOL;\n  CURLcode r = curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n  return r;   /* call before curl_easy_perform(); abort transfer if non-OK */\n}","typeGuard":null,"tryCatchPattern":"/* inside the CURLOPT_READFUNCTION callback, on the first chunk: */\nCURLcode r = curl_ws_start_frame(ctx->curl, CURLWS_TEXT, (curl_off_t)ctx->blen);\nif(r != CURLE_OK) {\n    ctx->perform_result = r;        /* surface to the curl_easy_perform caller */\n    return CURL_READFUNC_ABORT;     /* abort the transfer cleanly */\n}","preventionTips":["Initialize the easy handle with curl_easy_init() and verify it is non-NULL.","Use only ws:// or wss:// URLs and set CURLOPT_UPLOAD before perform.","Keep the payload length > 0 and <= CURL_MAX_WRITE_SIZE.","Stash the callback's CURLcode so the caller reads it after curl_easy_perform instead of silently aborting."],"tags":["websocket","libcurl","upload","frame","network"],"analyzedSha":"527573490eb2564b3d7c9dd51d8bff963b5d6303","analyzedAt":"2026-08-01T21:00:26.351Z","schemaVersion":2}