# Proper Error handling http\_open

**URL:** <https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252>\
**Category:** Help!\
**Tags:** how-to\
**Created:** [September 6, 2025, 6:27pm UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252 "2025-09-06T18:27:54Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Zandrenel](https://avatars.discourse-cdn.com/v4/letter/z/a4c791/32.png) [@Zandrenel](https://swi-prolog.discourse.group/u/Zandrenel)\
**Post date:** [September 6, 2025, 6:27pm UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/1 "2025-09-06T18:27:54Z")

</div>

I’m using: SWI-Prolog version 9.2.4

Hello,

I’ve been trying to have a webpage call another api and display the formatted results on a page. It works but when the other server is down, or throws an error my page returns the full exception string, what I’d prefer to do is error handle it and return just a formatted empty list when the second server is down. What would be the proper way to error handle?

My code looks like this:

```prolog
% the http reply endpoint
engine(Request) :-
    member(method(post), Request),!,
    http_read_data(Request, [query=Q|_], []),
    process_query(Q,R0),
    length(R0,Total),
    format_results(R0,R),
    reply_html_page(
	[title('search engine')],
	[
	    \html_requires(static('styles.css')),
	    \html_requires(static('themes.css')),
	    \nav_bar,
	    div(id(main),
		[
		    \description,
		    \query_form,
		    div(['Total Results: ',Total]),
		    div(R)
		]),
	    \footer   
	]).

```

```prolog
% The http_open call
process_query(Query, Message):-
    string_concat('/query/',Query,Path),
    parse_url(Url,
	      [ protocol(http),
		host('localhost'),
		port(8000),
		path(Path)
	      ]),
    write(Url),
    setup_call_cleanup(
	http_open(Url, In,
		  [ method(get),                
		    request_header('Content-Type'='application/json'),
		    request_header(accept='*/*'),		
		    cert_verify_hook(cert_accept_any),
		    status_code(200)
		  ]),
	(json_read(In, json(JSON)),
	 Message = JSON.message),
	close(In)).
process_query(_, []).

```

This is whats returned to the page when the other server is down

```prolog
Internal server error
Socket error: Connection refused
In:
[30] throw(error(socket_error(econnrefused,'Connection refused'),_1340))
[28] socket:tcp_connect('<garbage_collected>','<garbage_collected>',[visited(...),...|...]) at /usr/lib/swipl/library/ext/clib/socket.pl:471
[27] http_open:open_socket('<garbage_collected>',_1428,[visited(...),...|...]) at /usr/lib/swipl/library/ext/http/http/http_open.pl:951
[25] http_open:try_http_proxy(direct,[uri('http://localhost:8000/query/hello'),...|...],_1480,'<garbage_collected>') at /usr/lib/swipl/library/ext/http/http/http_open.pl:494
[23] <meta call>
[22] sig_atomic(search_engine:http_open('http://localhost:8000/query/hello',_1558,...)) <foreign>
[21] setup_call_cleanup('<garbage_collected>',search_engine:(...,...),search_engine:close(_1610)) at /usr/lib/swipl/boot/init.pl:681
[20] search_engine:process_query(hello,_1642) at /home/alek/Code/Prolog/swi-site/src/showcases/search_engine.pl:93
[19] search_engine:engine('<garbage_collected>') at /home/alek/Code/Prolog/swi-site/src/showcases/search_engine.pl:19
[18] http_dispatch:call_action(user:engine,[protocol(http),...|...]) at /usr/lib/swipl/library/ext/http/http/http_dispatch.pl:1043
[16] time:run_alarm_goal('<garbage_collected>','<garbage_collected>') at /usr/lib/swipl/library/ext/clib/time.pl:163
[15] setup_call_cleanup(time:alarm(300,...,...,...),time:run_alarm_goal(...,...),time:remove_alarm_notrace(...)) at /usr/lib/swipl/boot/init.pl:682
[14] time:call_with_time_limit(300,'<garbage_collected>','$no_ctx') at /usr/lib/swipl/library/ext/clib/time.pl:154
[12] http_dispatch:time_limit_action('<garbage_collected>','<garbage_collected>','<garbage_collected>') at /usr/lib/swipl/library/ext/http/http/http_dispatch.pl:1022
[8] httpd_wrapper:call_handler('<garbage_collected>',1,'<garbage_collected>') at /usr/lib/swipl/library/ext/http/http/http_wrapper.pl:329
[7] catch(httpd_wrapper:call_handler(...,1,...),_1952,httpd_wrapper:true) at /usr/lib/swipl/boot/init.pl:565
[6] httpd_wrapper:handler_with_output_to(user:http_dispatch,1,'<garbage_collected>',current_output,_2012) at /usr/lib/swipl/library/ext/http/http/http_wrapper.pl:308
[5] httpd_wrapper:handler_with_output_to('<garbage_collected>',1,'<garbage_collected>',<stream>(0x746d540232e0),'<garbage_collected>') at /usr/lib/swipl/library/ext/http/http/http_wrapper.pl:318

Note: some frames are missing due to last-call optimization.
Re-run your program in debug mode (:- debug.) to get more detail.

SWI-Prolog httpd at alek

```

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [September 6, 2025, 8:22pm UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/2 "2025-09-06T20:22:20Z")

</div>

To catch the thrown error, use catch/3 - here’s a potentially-convenient wrapper:

```prolog
catch_ok_exception(Goal, IfOk, IfException) :-
    catch(Goal, Err, true),
    ( var(Err)
    -> IfOk
    ; IfException
    ).

```

You are using `status_code(200)` - which will **fail** if the status code is not 200. Instead, use e.g. `status_code(StatusCode)` to have the code continue, and then check the `StatusCode` later, because it could be e.g. 504 HTTP error code.

---

<div class="post-metadata">

**Author:** ![Zandrenel](https://avatars.discourse-cdn.com/v4/letter/z/a4c791/32.png) [@Zandrenel](https://swi-prolog.discourse.group/u/Zandrenel)\
**Post date:** [September 7, 2025, 1:31am UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/3 "2025-09-07T01:31:00Z")

</div>

Thank you! I think I had some misunderstanding of how to use catch/3, next step is I will try adding different error code messages/handling. The working solution is this

```prolog
process_query(Query, Message):-string_concat(‘/query/’,Query,Path),parse_url(Url,[protocol(http),host(‘localhost’),port(8000),path(Path)]),write(Url),catch((http_open(Url, In,[method(get),request_header(‘Content-Type’=‘application/json’),request_header(accept=‘/’), cert_verify_hook(cert_accept_any)]),json_read(In, json(JSON)),Message = JSON.message),_Err,Message = [‘Server down’]).

```

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [September 7, 2025, 1:45am UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/4 "2025-09-07T01:45:12Z")

</div>

> [@Zandrenel](#):
>
> The working solution is this

Why are you not using what I suggested:

`status_code(StatusCode)`

The HTTP status code is vitally important, so this `StatusCode` variable needs to be checked by your code. It’s intended to be 200, but might not be.

---

<div class="post-metadata">

**Author:** ![Zandrenel](https://avatars.discourse-cdn.com/v4/letter/z/a4c791/32.png) [@Zandrenel](https://swi-prolog.discourse.group/u/Zandrenel)\
**Post date:** [September 7, 2025, 2:48am UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/5 "2025-09-07T02:48:41Z")

</div>

Using the wrapper I’m getting issues about the arguments being sufficiently instantiated. But I’m trying to add logic to handle various error codes right now, if I turn off the second api and the error gets thrown, the catch doesn’t seem to pass along any binding for the status code, though I’ll be running some tests and handling for status codes from my other api next.

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [September 7, 2025, 3:45am UTC](https://swi-prolog.discourse.group/t/proper-error-handling-http-open/9252/6 "2025-09-07T03:45:20Z")

</div>

The wrapper can be modified/customised, it’s just an example.
