curl/curl ยท error
curl_easy_perform() failed: %s
Error message
curl_easy_perform() failed: %s
What it means
Generic failure report from curl_easy_perform() in the websocket-updown example; result holds the CURLcode returned by the transfer. The message just renders curl_easy_strerror(result), so the underlying cause is whatever made the full WebSocket upload+download transfer fail.
Source
Thrown at docs/examples/websocket-updown.c:120
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
else
curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb);
/* tell curl that we want to send the payload */
rctx.curl = curl;
rctx.blen = sizeof(payload) - 1;
memcpy(rctx.buf, payload, rctx.blen);
curl_easy_setopt(curl, CURLOPT_READDATA, &rctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Perform the request, result gets the return code */
result = curl_easy_perform(curl);
/* Check for errors */
if(result != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(result));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return (int)result;
}
View on GitHub (pinned to 527573490e)
Solutions
- Read the rendered curl_easy_strerror text (e.g. 'Couldn\'t connect to server', 'SSL peer certificate...') to narrow the cause.
- Verify the wss:// URL resolves and that the endpoint supports WebSocket (expect HTTP 101 on upgrade).
- Check TLS: set CURLOPT_CAINFO to a valid CA bundle or fix the server certificate; confirm CURLOPT_SSL_VERIFYPEER behavior.
- Enable CURLOPT_VERBOSE to log the handshake and identify where the transfer aborts.
- Ensure the libcurl in use was built with WebSocket support.
Example fix
// before result = curl_easy_perform(curl); if(result != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result)); // after curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); result = curl_easy_perform(curl); if(result != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result));
Defensive patterns
Strategy: retry
Validate before calling
/* Pre-flight removes the argument/config class of failures.
Transient network failures are still handled by the retry loop. */
static CURLcode ws_perform_preflight(CURL *curl, const char *url) {
if(curl == NULL) return CURLE_BAD_FUNCTION_ARGUMENT;
if(url == NULL) return CURLE_URL_MALFORMAT;
if(strncmp(url, "ws://", 5) && strncmp(url, "wss://", 6))
return CURLE_UNSUPPORTED_PROTOCOL;
return CURLE_OK;
} Type guard
/* Narrow a CURLcode into an actionable bucket; drives retry policy. */
enum curl_kind { K_OK, K_TRANSIENT, K_PERMANENT };
static enum curl_kind curlcode_classify(CURLcode c) {
switch(c) {
case CURLE_OK: return K_OK;
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_COULDNT_RESOLVE_PROXY:
case CURLE_COULDNT_CONNECT:
case CURLE_WEIRD_SERVER_REPLY:
case CURLE_OPERATION_TIMEDOUT:
case CURLE_GOT_NOTHING:
case CURLE_SEND_ERROR:
case CURLE_RECV_ERROR:
case CURLE_PARTIAL_FILE:
case CURLE_HTTP2_STREAM:
case CURLE_AGAIN: return K_TRANSIENT;
default: return K_PERMANENT;
}
} Try / catch
CURLcode r;
for(unsigned attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
r = curl_easy_perform(curl);
if(curlcode_classify(r) != K_TRANSIENT) break; /* OK or permanent */
backoff_sleep(attempt); /* exp backoff + jitter */
}
if(r != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(r)); Prevention
- Set CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT so transient stalls surface as classifiable codes.
- Validate the ws/wss URL and handle before perform to eliminate argument-class errors.
- Bound the retry count and use exponential backoff with jitter.
- Do not retry permanent codes (e.g. CURLE_URL_MALFORMAT, CURLE_SSL_CONNECT_ERROR).
- Enable CURLOPT_NOSIGNAL on systems using multi-threaded timeouts.
When it happens
Trigger: Emitted at the end of main() when curl_easy_perform(curl) returns non-CURLE_OK for the wss:// upload/download transfer that has read_cb (upload) and write_cb (download) attached.
Common situations: DNS/TCP/TLS connection failures, invalid or unreachable ws/wss URL, server rejecting the WebSocket upgrade, expired/bad TLS certificates, proxy misconfiguration, timeouts, or a libcurl build without WebSocket support.
Related errors
- Failed to get '%s' [%s]
- curl_easy_perform() failed: %s
- curl_easy_perform() failed: %s
- curl_easy_perform() failed: %s
- curl_easy_perform() failed: %s
AI-assisted analysis of curl/curl@527573490e (2026-08-01).
Data as JSON: /data/errors/1f1e68a154ad034e.json.
Report an issue: GitHub.