curl/curl ยท error

error starting frame: %d

Error message

error starting frame: %d

What it means

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.

Source

Thrown at docs/examples/websocket-updown.c:72

  char buf[1024];
  size_t blen;
  size_t nsent;
};

static size_t read_cb(char *buf, size_t nitems, size_t buflen, void *p)
{
  struct read_ctx *ctx = p;
  size_t len = nitems * buflen;
  size_t left = ctx->blen - ctx->nsent;

  if(!ctx->nsent) {
    CURLcode result;
    /* On first call, set the FRAME information to be used (it defaults to
     * CURLWS_BINARY otherwise). */
    result = curl_ws_start_frame(ctx->curl, CURLWS_TEXT,
                                 (curl_off_t)ctx->blen);
    if(result != CURLE_OK) {
      fprintf(stderr, "error starting frame: %d\n", (int)result);
      return CURL_READFUNC_ABORT;
    }
  }
  fprintf(stderr, "read(len=%d, left=%d)\n", (int)len, (int)left);
  if(left) {
    if(left < len)
      len = left;
    memcpy(buf, ctx->buf + ctx->nsent, len);
    ctx->nsent += len;
    return len;
  }
  return 0;
}

int main(int argc, const char *argv[])
{
  CURL *curl;
  struct read_ctx rctx;

View on GitHub (pinned to 527573490e)

Solutions

  1. Use a ws:// or wss:// URL and ensure the server completes the WebSocket upgrade (HTTP 101) before the read callback runs.
  2. Verify the libcurl build supports WebSockets (curl --version shows 'WebSocket'); rebuild with --enable-websockets if missing.
  3. 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.
  4. 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).

Example fix

// before
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// after
curl_easy_setopt(curl, CURLOPT_URL, "wss://echo.websocket.events");
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
Defensive patterns

Strategy: validation

Validate before calling

static CURLcode ws_upload_preflight(CURL *curl, const char *url, size_t blen) {
  if(curl == NULL)          return CURLE_BAD_FUNCTION_ARGUMENT;
  if(blen == 0)             return CURLE_BAD_FUNCTION_ARGUMENT;
  if(strncmp(url, "ws://", 5) && strncmp(url, "wss://", 6))
                            return CURLE_UNSUPPORTED_PROTOCOL;
  CURLcode r = curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
  return r;   /* call before curl_easy_perform(); abort transfer if non-OK */
}

Try / catch

/* inside the CURLOPT_READFUNCTION callback, on the first chunk: */
CURLcode r = curl_ws_start_frame(ctx->curl, CURLWS_TEXT, (curl_off_t)ctx->blen);
if(r != CURLE_OK) {
    ctx->perform_result = r;        /* surface to the curl_easy_perform caller */
    return CURL_READFUNC_ABORT;     /* abort the transfer cleanly */
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of curl/curl@527573490e (2026-08-01). Data as JSON: /data/errors/6415e47c58cd8d43.json. Report an issue: GitHub.