Why doesn't try catch work with Lwt?

I am executing this code which works fine.

trailsList
  |> List.map buildUrl
  |> split 50

If I add 1 more step to this pipeline.

trailsList
  |> List.map buildUrl
  |> split 50
  |> Lwt_list.map_p(make_http_call);;

The code runs for all 800 items in my list but right at the end prints

"Exception:

Failure
“TLS to non-TCP currently unsupported: host=api.weather.gov endp=(Unknown "name resolution failed")”."

And other times it fails with

“Fatal error: exception SSL read() error: error:00000000:lib(0)::reason(0)”

In each case, there is no way for me to troubleshoot because I don’t know which line in my 800 item input URL list is causing this failure.

The implementation of make_http_calls is a little long but I have put try catch block on every step but the code never hits my catch block

let make_http_call ?(wait=5) = function 
  | Process(list) -> 
    list 
    |> List.map(fun str -> 
      try 
        str |> Uri.of_string |> Option.some
      with 
      | exn -> 
        "could not generate URI " ^
        "because of exception " ^
        (exn |> Printexc.to_string) 
        |> print_endline;
        None
    ) 
    |> Util.remove_none
    |> Lwt_list.map_p (fun uri -> 
      try
        uri |> Client.get |> Lwt.map(Option.some)
      with 
      | exn -> 
        "could not get data for " ^ 
        (uri |> Uri.to_string) ^ 
        "because of exception " ^ 
        (exn |> Printexc.to_string) 
        |> Lwt_io.(write stdout) |> Lwt.map( fun _ -> None)
    )
    |> Lwt.map(Util.remove_none)
    >>= (fun list -> 
      list |> Lwt_list.map_p(fun (resp, body) -> 
        let code = resp |> Response.status |> Cohttp.Code.code_of_status in
        if code == 200 then 
          try 
            body |> Cohttp_lwt.Body.to_string |> Lwt.map (Option.some)
          with 
          | exn -> exn |> Printexc.to_string |> Lwt_io.(write stdout) |> Lwt.map ( fun _ -> None)
        else begin 
          "did not get 200 response" |> Lwt_io.(write stdout) |> Lwt.map ( fun _ -> None )
        end
      )
    )
  | Wait -> 
    print_endline("going to wait now for " ^ (wait |> Int.to_string) ^ " seconds");Unix.sleep(wait); [None] |> Lwt.return

Why is it that the code fails without hitting any of my catch blocks? how to even troubleshoot where my code is failing.

In Lwt code exceptions are not thrown, promises are rejected. They have to be handled using operations provided by the Lwt library. See Module Lwt

6 Likes