{"id":"1f3090468e04c3f0","repo":"curl/curl","slug":"curl-easy-perform-failed-s-1f3090","errorCode":null,"errorMessage":"curl_easy_perform() failed: %s\n","messagePattern":"curl_easy_perform\\(\\) failed: (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"docs/examples/urlapi.c","lineNumber":68,"sourceCode":"  if(uc) {\n    fprintf(stderr, \"curl_url_set() failed: %s\", curl_url_strerror(uc));\n    goto cleanup;\n  }\n\n  /* get a curl handle */\n  curl = curl_easy_init();\n  if(curl) {\n    /* set urlp to use as working URL */\n    curl_easy_setopt(curl, CURLOPT_CURLU, urlp);\n    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);\n\n    /* only allow HTTP, TFTP and SFTP */\n    curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, \"http,tftp,sftp\");\n\n    result = curl_easy_perform(curl);\n    /* Check for errors */\n    if(result != CURLE_OK)\n      fprintf(stderr, \"curl_easy_perform() failed: %s\\n\",\n              curl_easy_strerror(result));\n  }\n\ncleanup:\n  curl_url_cleanup(urlp);\n  curl_easy_cleanup(curl);\n  curl_global_cleanup();\n  return (int)result;\n}\n","sourceCodeStart":50,"sourceCodeEnd":78,"githubUrl":"https://github.com/curl/curl/blob/527573490eb2564b3d7c9dd51d8bff963b5d6303/docs/examples/urlapi.c#L50-L78","documentation":"Printed by the urlapi.c example when curl_easy_perform() returns a non-CURLE_OK code while performing a transfer against the CURLU-configured URL. The %s is curl_easy_strerror(result). This is the standard transfer-failure path and occurs after the URL was successfully parsed by curl_url_set. It indicates the transfer itself (DNS/connect/TLS/HTTP) failed, not the URL setup.","triggerScenarios":"curl_easy_perform() is called after setting CURLOPT_CURLU to the parsed URL and restricting protocols with CURLOPT_PROTOCOLS_STR to 'http,tftp,sftp'; failure occurs if the host is unreachable, the protocol is blocked by the allow-list, DNS resolution fails, or the server returns a connection-level error.","commonSituations":"Setting CURLOPT_PROTOCOLS_STR to a scheme not matching the CURLU URL's scheme (e.g. an https URL when only http/tftp/sftp are allowed yields CURLE_UNSUPPORTED_PROTOCOL); pointing at an unreachable host; a typo in the URL host; TLS/cert issues if the scheme were https; restricting protocols too aggressively.","solutions":["Ensure the URL scheme is included in CURLOPT_PROTOCOLS_STR (e.g. add 'https' if the CURLU URL is https), since a mismatch yields CURLE_UNSUPPORTED_PROTOCOL","Verify host reachability and DNS for the URL set via curl_url_set / CURLOPT_CURLU","Inspect the CURLcode (curl_easy_strerror) and enable CURLOPT_VERBOSE (already set in the example) to see the exact stage that failed","Confirm curl_easy_setopt(curl, CURLOPT_CURLU, urlp) is called before curl_easy_perform() so the parsed URL is actually applied"],"exampleFix":"// before\ncurl_easy_setopt(curl, CURLOPT_CURLU, urlp);\ncurl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, \"http,tftp,sftp\");\nresult = curl_easy_perform(curl);\nif(result != CURLE_OK)\n  fprintf(stderr, \"curl_easy_perform() failed: %s\\n\", curl_easy_strerror(result));\n\n// after: allow the scheme actually present in the URL and log the code\ncurl_easy_setopt(curl, CURLOPT_CURLU, urlp);\ncurl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, \"http,https,tftp,sftp\");\nresult = curl_easy_perform(curl);\nif(result != CURLE_OK)\n  fprintf(stderr, \"curl_easy_perform() failed: %s (code %d)\\n\",\n          curl_easy_strerror(result), result);","handlingStrategy":"try-catch","validationCode":"/* Validate URL + options once before perform; cheap and removes most 128 causes. */\nstatic int preflight(CURL *c, const char *url) {\n  if (!url || !*url) return 0;\n  CURLU *u = curl_url();\n  CURLUcode uc = curl_url_set(u, CURLUPART_URL, url, CURLU_DEFAULT_SCHEME);\n  curl_url_cleanup(u);\n  if (uc != CURLUE_OK) return 0;\n  curl_easy_setopt(c, CURLOPT_URL, url);\n  curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT_MS, 5000L);\n  curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 30000L);\n  curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);\n  return 1;\n}\nif (!preflight(curl, argv[1])) { fprintf(stderr, \"preflight failed\\n\"); exit(EXIT_FAILURE); }","typeGuard":"/* Classify the perform() CURLcode so retry policy is data-driven. */\ntypedef enum { XFER_OK, XFER_RETRY, XFER_FAIL } xfer_t;\nstatic xfer_t classify(CURLcode rc) {\n  switch (rc) {\n    case CURLE_OK:                                  return XFER_OK;\n    case CURLE_COULDNT_CONNECT:\n    case CURLE_OPERATION_TIMEDOUT:\n    case CURLE_SEND_ERROR:\n    case CURLE_RECV_ERROR:\n    case CURLE_GOT_NOTHING:                         return XFER_RETRY;\n    default:                                        return XFER_FAIL;\n  }\n}","tryCatchPattern":"CURLcode rc;\nint attempt = 0;\ndo {\n  rc = curl_easy_perform(curl);\n  if (classify(rc) == XFER_RETRY && attempt < 3) {\n    usleep(200000L << attempt);          /* 0.2,0.4,0.8s backoff */\n    continue;\n  }\n  break;\n} while (++attempt);\nif (rc != CURLE_OK) {\n  fprintf(stderr, \"curl_easy_perform() failed: %s\\n\", curl_easy_strerror(rc));\n  curl_easy_cleanup(curl);\n  return EXIT_FAILURE;\n}","preventionTips":["Always set CURLOPT_CONNECTTIMEOUT_MS and CURLOPT_TIMEOUT_MS; the most common perform() 'failure' is an indefinite hang mistaken for a hard error.","Classify the CURLcode and only retry genuinely transient codes (connect/timeout/send/recv); do not retry malformed-URL or auth errors.","After perform, read CURLINFO_RESPONSE_CODE and treat 4xx/5xx as application errors even when curl returns CURLE_OK.","For HTTPS, set CURLOPT_CAINFO to a known bundle and CURLOPT_SSL_VERIFYPEER=1; SSL handshake failures are a frequent source of perform() errors."],"tags":["curl","http","transfer","urlapi","network","libcurl"],"analyzedSha":"527573490eb2564b3d7c9dd51d8bff963b5d6303","analyzedAt":"2026-08-01T21:00:26.351Z","schemaVersion":2}