All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alvaro Neira <alvaroneay@gmail.com>
To: netfilter-devel@vger.kernel.org
Subject: [libnftables PATCH v2] src: new error reporting approach for XML/JSON parsers
Date: Mon, 06 Jan 2014 00:51:14 +0100	[thread overview]
Message-ID: <20140105235114.3752.26544.stgit@Ph0enix> (raw)

From: Álvaro Neira Ayuso <alvaroneay@gmail.com>

I have added a new structure for reporting some errors in parser
that we can't cover with errno.

In this patch, we have three errors that we can't cover with errno:

NFT_PARSE_EBADINPUT : Bad XML/JSON format in the input
NFT_PARSE_EMISSINGNODE : Missing node in our input
NFT_PARSE_EBADTYPE : Wrong type value in a node

Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
---
 examples/nft-chain-json-add.c |   12 +++++
 examples/nft-chain-xml-add.c  |   12 +++++
 examples/nft-rule-json-add.c  |   12 +++++
 examples/nft-rule-xml-add.c   |   12 +++++
 examples/nft-set-json-add.c   |   13 +++++-
 examples/nft-table-json-add.c |   12 +++++
 examples/nft-table-xml-add.c  |   13 +++++-
 include/libnftables/chain.h   |    3 +
 include/libnftables/common.h  |   11 +++++
 include/libnftables/rule.h    |    3 +
 include/libnftables/ruleset.h |    3 +
 include/libnftables/set.h     |    6 ++-
 include/libnftables/table.h   |    3 +
 src/Makefile.am               |    1 
 src/chain.c                   |   75 ++++++++++++++++++++--------------
 src/common.c                  |   32 +++++++++++++++
 src/expr/bitwise.c            |   26 ++++++------
 src/expr/byteorder.c          |   27 +++++++-----
 src/expr/cmp.c                |   20 +++++----
 src/expr/counter.c            |   16 +++++--
 src/expr/ct.c                 |   19 +++++----
 src/expr/data_reg.c           |   54 ++++++++++++++-----------
 src/expr/data_reg.h           |    6 ++-
 src/expr/exthdr.c             |   23 ++++++----
 src/expr/immediate.c          |   14 ++++--
 src/expr/limit.c              |   17 +++++---
 src/expr/log.c                |   27 ++++++++----
 src/expr/lookup.c             |   18 +++++---
 src/expr/match.c              |   10 +++--
 src/expr/meta.c               |   14 ++++--
 src/expr/nat.c                |   30 +++++++-------
 src/expr/payload.c            |   24 ++++++-----
 src/expr/reject.c             |   16 +++++--
 src/expr/target.c             |   10 +++--
 src/expr_ops.h                |    6 ++-
 src/internal.h                |   90 +++++++++++++++++++++++++++++------------
 src/jansson.c                 |   83 ++++++++++++++++++++++++++------------
 src/libnftables.map           |    5 ++
 src/mxml.c                    |   83 ++++++++++++++++++++++++++++----------
 src/rule.c                    |   69 ++++++++++++++++++-------------
 src/ruleset.c                 |   72 +++++++++++++++++++--------------
 src/set.c                     |   70 ++++++++++++++++++--------------
 src/set_elem.c                |   21 +++++-----
 src/table.c                   |   44 ++++++++++++--------
 tests/nft-parsing-test.c      |   39 +++++++++++-------
 45 files changed, 761 insertions(+), 415 deletions(-)

diff --git a/examples/nft-chain-json-add.c b/examples/nft-chain-json-add.c
index 50cb29f..1802fb0 100644
--- a/examples/nft-chain-json-add.c
+++ b/examples/nft-chain-json-add.c
@@ -39,6 +39,7 @@ int main(int argc, char *argv[])
 	uint16_t family;
 	char json[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <json-file>\n", argv[0]);
@@ -63,10 +64,16 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
 	close(fd);
 
-	if (nft_chain_parse(c, NFT_PARSE_JSON, json) < 0) {
-		printf("E: Unable to parse JSON file: %s\n", strerror(errno));
+	if (nft_chain_parse(c, NFT_PARSE_JSON, json, err) < 0) {
+		nft_parse_perror("Unable to parse JSON file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -82,6 +89,7 @@ int main(int argc, char *argv[])
 	nft_chain_nlmsg_build_payload(nlh, c);
 
 	nft_chain_free(c);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-chain-xml-add.c b/examples/nft-chain-xml-add.c
index 03a2950..79b1541 100644
--- a/examples/nft-chain-xml-add.c
+++ b/examples/nft-chain-xml-add.c
@@ -37,6 +37,7 @@ int main(int argc, char *argv[])
 	uint16_t family;
 	char xml[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <xml-file>\n", argv[0]);
@@ -49,6 +50,12 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
         fd = open(argv[1], O_RDONLY);
         if (fd < 0) {
                 perror("open");
@@ -63,8 +70,8 @@ int main(int argc, char *argv[])
 
 	close(fd);
 
-	if (nft_chain_parse(c, NFT_PARSE_XML, xml) < 0) {
-		printf("E: Unable to parse XML file: %s\n", strerror(errno));
+	if (nft_chain_parse(c, NFT_PARSE_XML, xml, err) < 0) {
+		nft_parse_perror("Unable to parse XML file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -80,6 +87,7 @@ int main(int argc, char *argv[])
 	nft_chain_nlmsg_build_payload(nlh, c);
 
 	nft_chain_free(c);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-rule-json-add.c b/examples/nft-rule-json-add.c
index 8659081..de1fb54 100644
--- a/examples/nft-rule-json-add.c
+++ b/examples/nft-rule-json-add.c
@@ -38,6 +38,7 @@ int main(int argc, char *argv[])
 	uint8_t family;
 	char json[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <json-file>\n", argv[0]);
@@ -63,8 +64,14 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	if (nft_rule_parse(r, NFT_PARSE_JSON, json) < 0) {
-		printf("E: Unable to parse JSON file: %s\n", strerror(errno));
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
+	if (nft_rule_parse(r, NFT_PARSE_JSON, json, err) < 0) {
+		nft_parse_perror("Unable to parse JSON file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -80,6 +87,7 @@ int main(int argc, char *argv[])
 				       seq);
 	nft_rule_nlmsg_build_payload(nlh, r);
 	nft_rule_free(r);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-rule-xml-add.c b/examples/nft-rule-xml-add.c
index ce33fe7..8a7685d 100644
--- a/examples/nft-rule-xml-add.c
+++ b/examples/nft-rule-xml-add.c
@@ -38,6 +38,7 @@ int main(int argc, char *argv[])
 	uint8_t family;
 	char xml[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <xml-file>\n", argv[0]);
@@ -63,8 +64,14 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	if (nft_rule_parse(r, NFT_PARSE_XML, xml) < 0) {
-		printf("E: Unable to parse XML file: %s\n", strerror(errno));
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
+	if (nft_rule_parse(r, NFT_PARSE_XML, xml, err) < 0) {
+		nft_parse_perror("Unable to parse XML file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -80,6 +87,7 @@ int main(int argc, char *argv[])
 				       seq);
 	nft_rule_nlmsg_build_payload(nlh, r);
 	nft_rule_free(r);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-set-json-add.c b/examples/nft-set-json-add.c
index 9a4aa48..94d27e6 100644
--- a/examples/nft-set-json-add.c
+++ b/examples/nft-set-json-add.c
@@ -38,6 +38,7 @@ int main(int argc, char *argv[])
 	uint16_t family;
 	char json[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <json-file>\n", argv[0]);
@@ -62,10 +63,17 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
+
 	close(fd);
 
-	if (nft_set_parse(s, NFT_PARSE_JSON, json) < 0) {
-		printf("E: Unable to parse JSON file: %s\n", strerror(errno));
+	if (nft_set_parse(s, NFT_PARSE_JSON, json, err) < 0) {
+		nft_parse_perror("Unable to parse JSON file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -80,6 +88,7 @@ int main(int argc, char *argv[])
 					NLM_F_CREATE|NLM_F_ACK, seq);
 	nft_set_nlmsg_build_payload(nlh, s);
 	nft_set_free(s);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-table-json-add.c b/examples/nft-table-json-add.c
index 6b16c7f..f3a57c0 100644
--- a/examples/nft-table-json-add.c
+++ b/examples/nft-table-json-add.c
@@ -39,6 +39,7 @@ int main(int argc, char *argv[])
 	uint16_t family;
 	char json[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <json-file>\n", argv[0]);
@@ -64,8 +65,14 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	if (nft_table_parse(t, NFT_PARSE_JSON, json) < 0) {
-		printf("E: Unable to parse JSON file: %s\n", strerror(errno));
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
+	if (nft_table_parse(t, NFT_PARSE_JSON, json, err) < 0) {
+		nft_parse_perror("Unable to parse JSON file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -80,6 +87,7 @@ int main(int argc, char *argv[])
 					NLM_F_CREATE|NLM_F_ACK, seq);
 	nft_table_nlmsg_build_payload(nlh, t);
 	nft_table_free(t);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/examples/nft-table-xml-add.c b/examples/nft-table-xml-add.c
index 6a9163b..edef1d4 100644
--- a/examples/nft-table-xml-add.c
+++ b/examples/nft-table-xml-add.c
@@ -23,6 +23,7 @@
 
 #include <libmnl/libmnl.h>
 #include <libnftables/table.h>
+#include <libnftables/common.h>
 
 int main(int argc, char *argv[])
 {
@@ -35,6 +36,7 @@ int main(int argc, char *argv[])
 	uint16_t family;
 	char xml[4096];
 	char reprint[4096];
+	struct nft_parse_err *err;
 
 	if (argc < 2) {
 		printf("Usage: %s <xml-file>\n", argv[0]);
@@ -60,8 +62,14 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	if (nft_table_parse(t, NFT_PARSE_XML, xml) < 0) {
-		printf("E: Unable to parse XML file: %s\n", strerror(errno));
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
+	if (nft_table_parse(t, NFT_PARSE_XML, xml, err) < 0) {
+		nft_parse_perror("Unable to parse XML file", err);
 		exit(EXIT_FAILURE);
 	}
 
@@ -76,6 +84,7 @@ int main(int argc, char *argv[])
 					NLM_F_CREATE|NLM_F_ACK, seq);
 	nft_table_nlmsg_build_payload(nlh, t);
 	nft_table_free(t);
+	nft_parse_err_free(err);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
diff --git a/include/libnftables/chain.h b/include/libnftables/chain.h
index 8b4eab9..dec1a77 100644
--- a/include/libnftables/chain.h
+++ b/include/libnftables/chain.h
@@ -51,7 +51,8 @@ struct nlmsghdr;
 
 void nft_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_chain *t);
 
-int nft_chain_parse(struct nft_chain *c, enum nft_parse_type type, const char *data);
+int nft_chain_parse(struct nft_chain *c, enum nft_parse_type type,
+		    const char *data, struct nft_parse_err *err);
 int nft_chain_snprintf(char *buf, size_t size, struct nft_chain *t, uint32_t type, uint32_t flags);
 int nft_chain_fprintf(FILE *fp, struct nft_chain *c, uint32_t type, uint32_t flags);
 
diff --git a/include/libnftables/common.h b/include/libnftables/common.h
index 9cd92b2..1ef88ba 100644
--- a/include/libnftables/common.h
+++ b/include/libnftables/common.h
@@ -1,6 +1,12 @@
 #ifndef _LIBNFTABLES_COMMON_H_
 #define _LIBNFTABLES_COMMON_H_
 
+enum {
+	NFT_PARSE_EBADINPUT	= 0,
+	NFT_PARSE_EMISSINGNODE,
+	NFT_PARSE_EBADTYPE,
+};
+
 enum nft_output_type {
 	NFT_OUTPUT_DEFAULT	= 0,
 	NFT_OUTPUT_XML,
@@ -14,7 +20,12 @@ enum nft_parse_type {
 	NFT_PARSE_MAX,
 };
 
+struct nft_parse_err;
+
 struct nlmsghdr *nft_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
 				     uint16_t type, uint32_t seq);
 
+struct nft_parse_err *nft_parse_err_alloc(void);
+void nft_parse_err_free(struct nft_parse_err *);
+int nft_parse_perror(const char *str, struct nft_parse_err *err);
 #endif
diff --git a/include/libnftables/rule.h b/include/libnftables/rule.h
index 86dbc17..1510203 100644
--- a/include/libnftables/rule.h
+++ b/include/libnftables/rule.h
@@ -47,7 +47,8 @@ struct nlmsghdr;
 
 void nft_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_rule *t);
 
-int nft_rule_parse(struct nft_rule *r, enum nft_parse_type type, const char *data);
+int nft_rule_parse(struct nft_rule *r, enum nft_parse_type type,
+		   const char *data, struct nft_parse_err *err);
 int nft_rule_snprintf(char *buf, size_t size, struct nft_rule *t, uint32_t type, uint32_t flags);
 int nft_rule_fprintf(FILE *fp, struct nft_rule *r, uint32_t type, uint32_t flags);
 
diff --git a/include/libnftables/ruleset.h b/include/libnftables/ruleset.h
index 1ec3059..b523346 100644
--- a/include/libnftables/ruleset.h
+++ b/include/libnftables/ruleset.h
@@ -30,7 +30,8 @@ void nft_ruleset_attr_unset(struct nft_ruleset *r, uint16_t attr);
 void nft_ruleset_attr_set(struct nft_ruleset *r, uint16_t attr, void *data);
 const void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr);
 
-int nft_ruleset_parse(struct nft_ruleset *rs, enum nft_parse_type type, const char *data);
+int nft_ruleset_parse(struct nft_ruleset *rs, enum nft_parse_type type,
+		      const char *data, struct nft_parse_err *err);
 int nft_ruleset_snprintf(char *buf, size_t size, const struct nft_ruleset *rs, uint32_t type, uint32_t flags);
 int nft_ruleset_fprintf(FILE *fp, const struct nft_ruleset *rs, uint32_t type, uint32_t flags);
 
diff --git a/include/libnftables/set.h b/include/libnftables/set.h
index 13ac857..9711729 100644
--- a/include/libnftables/set.h
+++ b/include/libnftables/set.h
@@ -60,7 +60,8 @@ struct nft_set *nft_set_list_iter_cur(struct nft_set_list_iter *iter);
 struct nft_set *nft_set_list_iter_next(struct nft_set_list_iter *iter);
 void nft_set_list_iter_destroy(struct nft_set_list_iter *iter);
 
-int nft_set_parse(struct nft_set *s, enum nft_parse_type type, const char *data);
+int nft_set_parse(struct nft_set *s, enum nft_parse_type type,
+		  const char *data, struct nft_parse_err *err);
 
 /*
  * Set elements
@@ -98,7 +99,8 @@ void nft_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set_elem
 
 int nft_set_elem_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set_elem *s);
 
-int nft_set_elem_parse(struct nft_set_elem *e, enum nft_parse_type type, const char *data);
+int nft_set_elem_parse(struct nft_set_elem *e, enum nft_parse_type type,
+		       const char *data, struct nft_parse_err *err);
 int nft_set_elem_snprintf(char *buf, size_t size, struct nft_set_elem *s, uint32_t type, uint32_t flags);
 int nft_set_elem_fprintf(FILE *fp, struct nft_set_elem *se, uint32_t type, uint32_t flags);
 
diff --git a/include/libnftables/table.h b/include/libnftables/table.h
index be60da9..80f2349 100644
--- a/include/libnftables/table.h
+++ b/include/libnftables/table.h
@@ -39,7 +39,8 @@ struct nlmsghdr;
 
 void nft_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_table *t);
 
-int nft_table_parse(struct nft_table *t, enum nft_parse_type type, const char *data);
+int nft_table_parse(struct nft_table *t, enum nft_parse_type type,
+		    const char *data, struct nft_parse_err *err);
 int nft_table_snprintf(char *buf, size_t size, struct nft_table *t, uint32_t type, uint32_t flags);
 int nft_table_fprintf(FILE *fp, struct nft_table *t, uint32_t type, uint32_t flags);
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 83ab658..fc13e46 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,7 @@ lib_LTLIBRARIES = libnftables.la
 libnftables_la_LIBADD = ${LIBMNL_LIBS} ${LIBXML_LIBS} ${LIBJSON_LIBS}
 libnftables_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnftables.map \
 			 -version-info $(LIBVERSION)
+
 libnftables_la_SOURCES = utils.c		\
 			 common.c		\
 			 table.c		\
diff --git a/src/chain.c b/src/chain.c
index a0004b5..a4ddb06 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -498,7 +498,8 @@ static inline int nft_str2hooknum(int family, const char *hook)
 }
 
 #ifdef JSON_PARSING
-int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
+int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree,
+			    struct nft_parse_err *err)
 {
 	json_t *root;
 	uint64_t uval64;
@@ -506,37 +507,40 @@ int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
 	int32_t val32;
 	const char *valstr;
 
-	root = nft_jansson_get_node(tree, "chain");
+	root = nft_jansson_get_node(tree, "chain", err);
 	if (root == NULL)
 		return -1;
 
-	valstr = nft_jansson_parse_str(root, "name");
+	valstr = nft_jansson_parse_str(root, "name", err);
 	if (valstr == NULL)
 		goto err;
 
 	nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_NAME, valstr);
 
-	if (nft_jansson_parse_val(root, "handle", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "handle", NFT_TYPE_U64, &uval64,
+				  err) < 0)
 		goto err;
 
 	nft_chain_attr_set_u64(c,NFT_CHAIN_ATTR_HANDLE, uval64);
 
-	if (nft_jansson_parse_val(root, "bytes", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "bytes", NFT_TYPE_U64, &uval64,
+				  err) < 0)
 		goto err;
 
 	nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_BYTES, uval64);
 
-	if (nft_jansson_parse_val(root, "packets", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "packets", NFT_TYPE_U64, &uval64,
+				  err) < 0)
 		goto err;
 
 	nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_PACKETS, uval64);
 
-	if (nft_jansson_parse_family(root, &val32) != 0)
+	if (nft_jansson_parse_family(root, &val32, err) != 0)
 		goto err;
 
 	nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_FAMILY, val32);
 
-	valstr = nft_jansson_parse_str(root, "table");
+	valstr = nft_jansson_parse_str(root, "table", err);
 
 	if (valstr == NULL)
 		goto err;
@@ -544,7 +548,7 @@ int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
 	nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_TABLE, valstr);
 
 	if (nft_jansson_node_exist(root, "hooknum")) {
-		valstr = nft_jansson_parse_str(root, "type");
+		valstr = nft_jansson_parse_str(root, "type", err);
 
 		if (valstr == NULL)
 			goto err;
@@ -552,12 +556,12 @@ int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
 		nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_TYPE, valstr);
 
 		if (nft_jansson_parse_val(root, "prio", NFT_TYPE_S32,
-					  &val32) < 0)
+					  &val32, err) < 0)
 			goto err;
 
 		nft_chain_attr_set_s32(c, NFT_CHAIN_ATTR_PRIO, val32);
 
-		valstr = nft_jansson_parse_str(root, "hooknum");
+		valstr = nft_jansson_parse_str(root, "hooknum", err);
 		if (valstr == NULL)
 			goto err;
 
@@ -567,7 +571,7 @@ int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
 
 		nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_HOOKNUM, val32);
 
-		valstr = nft_jansson_parse_str(root, "policy");
+		valstr = nft_jansson_parse_str(root, "policy", err);
 		if (valstr == NULL)
 			goto err;
 
@@ -587,17 +591,18 @@ err:
 }
 #endif
 
-static int nft_chain_json_parse(struct nft_chain *c, const char *json)
+static int nft_chain_json_parse(struct nft_chain *c, const char *json,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	json_t *tree;
 	json_error_t error;
 
-	tree = nft_jansson_create_root(json, &error);
+	tree = nft_jansson_create_root(json, &error, err);
 	if (tree == NULL)
 		return -1;
 
-	return nft_jansson_parse_chain(c, tree);
+	return nft_jansson_parse_chain(c, tree, err);
 #else
 	errno = EOPNOTSUPP;
 	return -1;
@@ -605,13 +610,14 @@ static int nft_chain_json_parse(struct nft_chain *c, const char *json)
 }
 
 #ifdef XML_PARSING
-int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
+int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c,
+			 struct nft_parse_err *err)
 {
 	const char *table, *name, *hooknum_str, *policy_str, *type;
 	int family, hooknum, policy;
 
 	name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
-				  NFT_XML_MAND);
+				  NFT_XML_MAND, err);
 	if (name == NULL)
 		return -1;
 
@@ -619,25 +625,25 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 	c->flags |= (1 << NFT_CHAIN_ATTR_NAME);
 
 	if (nft_mxml_num_parse(tree, "handle", MXML_DESCEND_FIRST, BASE_DEC,
-			       &c->handle, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &c->handle, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	c->flags |= (1 << NFT_CHAIN_ATTR_HANDLE);
 
 	if (nft_mxml_num_parse(tree, "bytes", MXML_DESCEND_FIRST, BASE_DEC,
-			       &c->bytes, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &c->bytes, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	c->flags |= (1 << NFT_CHAIN_ATTR_BYTES);
 
 	if (nft_mxml_num_parse(tree, "packets", MXML_DESCEND_FIRST, BASE_DEC,
-			       &c->packets, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &c->packets, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	c->flags |= (1 << NFT_CHAIN_ATTR_PACKETS);
 
 	table = nft_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
-				   NFT_XML_MAND);
+				   NFT_XML_MAND, err);
 	if (table == NULL)
 		return -1;
 
@@ -648,7 +654,7 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 	c->flags |= (1 << NFT_CHAIN_ATTR_TABLE);
 
 	family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
-				       NFT_XML_MAND);
+				       NFT_XML_MAND, err);
 	if (family < 0)
 		return -1;
 
@@ -656,7 +662,7 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 	c->flags |= (1 << NFT_CHAIN_ATTR_FAMILY);
 
 	hooknum_str = nft_mxml_str_parse(tree, "hooknum", MXML_DESCEND_FIRST,
-					 NFT_XML_OPT);
+					 NFT_XML_OPT, err);
 	if (hooknum_str != NULL) {
 		hooknum = nft_str2hooknum(c->family, hooknum_str);
 		if (hooknum < 0)
@@ -666,7 +672,7 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 		c->flags |= (1 << NFT_CHAIN_ATTR_HOOKNUM);
 
 		type = nft_mxml_str_parse(tree, "type", MXML_DESCEND_FIRST,
-					  NFT_XML_MAND);
+					  NFT_XML_MAND, err);
 		if (type == NULL)
 			return -1;
 
@@ -679,14 +685,14 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 
 		if (nft_mxml_num_parse(tree, "prio", MXML_DESCEND, BASE_DEC,
 				       &c->prio, NFT_TYPE_S32,
-				       NFT_XML_MAND) != 0)
+				       NFT_XML_MAND, err) != 0)
 			return -1;
 
 		c->flags |= (1 << NFT_CHAIN_ATTR_PRIO);
 
 		policy_str = nft_mxml_str_parse(tree, "policy",
 						MXML_DESCEND_FIRST,
-						NFT_XML_MAND);
+						NFT_XML_MAND, err);
 		if (policy_str == NULL)
 			return -1;
 
@@ -702,15 +708,16 @@ int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c)
 }
 #endif
 
-static int nft_chain_xml_parse(struct nft_chain *c, const char *xml)
+static int nft_chain_xml_parse(struct nft_chain *c, const char *xml,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	int ret;
-	mxml_node_t *tree = nft_mxml_build_tree(xml, "chain");
+	mxml_node_t *tree = nft_mxml_build_tree(xml, "chain", err);
 	if (tree == NULL)
 		return -1;
 
-	ret = nft_mxml_chain_parse(tree, c);
+	ret = nft_mxml_chain_parse(tree, c, err);
 	mxmlDelete(tree);
 	return ret;
 #else
@@ -720,16 +727,17 @@ static int nft_chain_xml_parse(struct nft_chain *c, const char *xml)
 }
 
 int nft_chain_parse(struct nft_chain *c, enum nft_parse_type type,
-		    const char *data)
+		    const char *data, struct nft_parse_err *err)
 {
 	int ret;
+	struct nft_parse_err perr;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_chain_xml_parse(c, data);
+		ret = nft_chain_xml_parse(c, data, &perr);
 		break;
 	case NFT_PARSE_JSON:
-		ret = nft_chain_json_parse(c, data);
+		ret = nft_chain_json_parse(c, data, &perr);
 		break;
 	default:
 		ret = -1;
@@ -737,6 +745,9 @@ int nft_chain_parse(struct nft_chain *c, enum nft_parse_type type,
 		break;
 	}
 
+	if (err != NULL)
+		*err = perr;
+
 	return ret;
 }
 EXPORT_SYMBOL(nft_chain_parse);
diff --git a/src/common.c b/src/common.c
index f03e730..81a8125 100644
--- a/src/common.c
+++ b/src/common.c
@@ -14,6 +14,7 @@
 #include <libnftables/common.h>
 
 #include "internal.h"
+#include<stdlib.h>
 
 struct nlmsghdr *nft_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
 				     uint16_t type, uint32_t seq)
@@ -33,4 +34,35 @@ struct nlmsghdr *nft_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
 
 	return nlh;
 }
+
 EXPORT_SYMBOL(nft_nlmsg_build_hdr);
+
+struct nft_parse_err *nft_parse_err_alloc(void)
+{
+	return calloc(1, sizeof(struct nft_parse_err));
+}
+EXPORT_SYMBOL(nft_parse_err_alloc);
+
+void nft_parse_err_free(struct nft_parse_err *err)
+{
+	xfree(err);
+}
+EXPORT_SYMBOL(nft_parse_err_free);
+
+int nft_parse_perror(const char *str, struct nft_parse_err *err)
+{
+	switch (err->error) {
+	case NFT_PARSE_EBADINPUT:
+		return fprintf(stderr, "%s : Bad input format in line %d column %d\n",
+		       str, err->line, err->column);
+	case NFT_PARSE_EMISSINGNODE:
+		return fprintf(stderr, "%s : Node \"%s\" not found\n",
+				str, err->node_name);
+	case NFT_PARSE_EBADTYPE:
+		return fprintf(stderr, "%s: Invalid type in node \"%s\"\n",
+				str, err->node_name);
+	default:
+		return fprintf(stderr, "Undefined error\n");
+	}
+}
+EXPORT_SYMBOL(nft_parse_perror);
diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c
index bcec516..3c4f644 100644
--- a/src/expr/bitwise.c
+++ b/src/expr/bitwise.c
@@ -181,35 +181,36 @@ nft_rule_expr_bitwise_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
-nft_rule_expr_bitwise_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_bitwise_json_parse(struct nft_rule_expr *e, json_t *root,
+				 struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	struct nft_expr_bitwise *bitwise = nft_expr_data(e);
 	uint32_t reg, len;
 
-	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_SREG, reg);
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_DREG, reg);
 
-	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &len) < 0)
+	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &len, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_LEN, len);
 
 	if (nft_jansson_data_reg_parse(root, "mask",
-				       &bitwise->mask) != DATA_VALUE)
+				       &bitwise->mask, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BITWISE_MASK);
 
 	if (nft_jansson_data_reg_parse(root, "xor",
-				       &bitwise->xor) != DATA_VALUE)
+				       &bitwise->xor, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BITWISE_XOR);
@@ -225,20 +226,21 @@ nft_rule_expr_bitwise_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_bitwise *bitwise = nft_expr_data(e);
 	int32_t reg;
 
-	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
 	bitwise->sreg = reg;
 	e->flags |= (1 << NFT_EXPR_BITWISE_SREG);
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
@@ -247,19 +249,19 @@ nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST,
 			       BASE_DEC, &bitwise->len, NFT_TYPE_U8,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BITWISE_LEN);
 
 	if (nft_mxml_data_reg_parse(tree, "mask", &bitwise->mask,
-				    NFT_XML_MAND) != DATA_VALUE)
+				    NFT_XML_MAND, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BITWISE_MASK);
 
 	if (nft_mxml_data_reg_parse(tree, "xor", &bitwise->xor,
-				    NFT_XML_MAND) != DATA_VALUE)
+				    NFT_XML_MAND, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BITWISE_XOR);
diff --git a/src/expr/byteorder.c b/src/expr/byteorder.c
index 7224c82..d6beba3 100644
--- a/src/expr/byteorder.c
+++ b/src/expr/byteorder.c
@@ -194,24 +194,25 @@ static inline int nft_str2ntoh(const char *op)
 }
 
 static int
-nft_rule_expr_byteorder_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_byteorder_json_parse(struct nft_rule_expr *e, json_t *root,
+				   struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *op;
 	uint32_t uval32;
 	int ntoh;
 
-	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SREG, uval32);
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_DREG, uval32);
 
-	op = nft_jansson_parse_str(root, "op");
+	op = nft_jansson_parse_str(root, "op", err);
 	if (op == NULL)
 		return -1;
 
@@ -221,12 +222,12 @@ nft_rule_expr_byteorder_json_parse(struct nft_rule_expr *e, json_t *root)
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_OP, ntoh);
 
-	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_LEN, uval32);
 
-	if (nft_jansson_parse_val(root, "size", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "size", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SIZE, uval32);
@@ -239,28 +240,30 @@ nft_rule_expr_byteorder_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_byteorder_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_byteorder_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				  struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_byteorder *byteorder = nft_expr_data(e);
 	const char *op;
 	int32_t reg, ntoh;
 
-	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
 	byteorder->sreg = reg;
 	e->flags |= (1 << NFT_EXPR_BYTEORDER_SREG);
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
 	byteorder->dreg = reg;
 	e->flags |= (1 << NFT_EXPR_BYTEORDER_DREG);
 
-	op = nft_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFT_XML_MAND);
+	op = nft_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFT_XML_MAND,
+				err);
 	if (op == NULL)
 		return -1;
 
@@ -273,14 +276,14 @@ nft_rule_expr_byteorder_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
 			       &byteorder->len, NFT_TYPE_U8,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BYTEORDER_LEN);
 
 	if (nft_mxml_num_parse(tree, "size", MXML_DESCEND_FIRST, BASE_DEC,
 			       &byteorder->size, NFT_TYPE_U8,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_BYTEORDER_SIZE);
diff --git a/src/expr/cmp.c b/src/expr/cmp.c
index 246f22f..ca1503c 100644
--- a/src/expr/cmp.c
+++ b/src/expr/cmp.c
@@ -174,7 +174,8 @@ static inline int nft_str2cmp(const char *op)
 	}
 }
 
-static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root,
+					struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	struct nft_expr_cmp *cmp = nft_expr_data(e);
@@ -182,12 +183,12 @@ static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root)
 	uint32_t uval32;
 	int base;
 
-	if (nft_jansson_parse_val(root, "sreg", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "sreg", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_CMP_SREG, uval32);
 
-	op = nft_jansson_parse_str(root, "op");
+	op = nft_jansson_parse_str(root, "op", err);
 	if (op == NULL)
 		return -1;
 
@@ -198,7 +199,7 @@ static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root)
 	nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, base);
 
 	if (nft_jansson_data_reg_parse(root, "cmpdata",
-				       &cmp->data) != DATA_VALUE)
+				       &cmp->data, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_CMP_DATA);
@@ -210,21 +211,23 @@ static int nft_rule_expr_cmp_json_parse(struct nft_rule_expr *e, json_t *root)
 #endif
 }
 
-static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_cmp *cmp = nft_expr_data(e);
 	const char *op;
 	int32_t reg, op_value;
 
-	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
 	cmp->sreg = reg;
 	e->flags |= (1 << NFT_EXPR_CMP_SREG);
 
-	op = nft_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFT_XML_MAND);
+	op = nft_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFT_XML_MAND,
+				err);
 	if (op == NULL)
 		return -1;
 
@@ -236,7 +239,8 @@ static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	e->flags |= (1 << NFT_EXPR_CMP_OP);
 
 	if (nft_mxml_data_reg_parse(tree, "cmpdata",
-				    &cmp->data, NFT_XML_MAND) != DATA_VALUE)
+				    &cmp->data, NFT_XML_MAND,
+				    err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_CMP_DATA);
diff --git a/src/expr/counter.c b/src/expr/counter.c
index 4919a69..11afb83 100644
--- a/src/expr/counter.c
+++ b/src/expr/counter.c
@@ -119,17 +119,18 @@ nft_rule_expr_counter_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
-nft_rule_expr_counter_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_counter_json_parse(struct nft_rule_expr *e, json_t *root,
+				 struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	uint64_t uval64;
 
-	if (nft_jansson_parse_val(root, "pkts", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "pkts", NFT_TYPE_U64, &uval64, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u64(e, NFT_EXPR_CTR_PACKETS, uval64);
 
-	if (nft_jansson_parse_val(root, "bytes", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "bytes", NFT_TYPE_U64, &uval64, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u64(e, NFT_EXPR_CTR_BYTES, uval64);
@@ -142,19 +143,22 @@ nft_rule_expr_counter_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_counter_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_counter_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_counter *ctr = nft_expr_data(e);
 
 	if (nft_mxml_num_parse(tree, "pkts", MXML_DESCEND_FIRST, BASE_DEC,
-			       &ctr->pkts, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &ctr->pkts, NFT_TYPE_U64, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_CTR_PACKETS);
 
 	if (nft_mxml_num_parse(tree, "bytes", MXML_DESCEND_FIRST, BASE_DEC,
-			       &ctr->bytes, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &ctr->bytes, NFT_TYPE_U64, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_CTR_BYTES);
diff --git a/src/expr/ct.c b/src/expr/ct.c
index 46e3cef..59d05a5 100644
--- a/src/expr/ct.c
+++ b/src/expr/ct.c
@@ -178,7 +178,8 @@ static inline int str2ctkey(const char *ctkey)
 	return -1;
 }
 
-static int nft_rule_expr_ct_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_ct_json_parse(struct nft_rule_expr *e, json_t *root,
+				       struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *key_str;
@@ -186,13 +187,13 @@ static int nft_rule_expr_ct_json_parse(struct nft_rule_expr *e, json_t *root)
 	uint8_t dir;
 	int key;
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_CT_DREG, reg);
 
 	if (nft_jansson_node_exist(root, "key")) {
-		key_str = nft_jansson_parse_str(root, "key");
+		key_str = nft_jansson_parse_str(root, "key", err);
 		if (key_str == NULL)
 			return -1;
 
@@ -205,7 +206,8 @@ static int nft_rule_expr_ct_json_parse(struct nft_rule_expr *e, json_t *root)
 	}
 
 	if (nft_jansson_node_exist(root, "dir")) {
-		if (nft_jansson_parse_val(root, "dir", NFT_TYPE_U8, &dir) < 0)
+		if (nft_jansson_parse_val(root, "dir", NFT_TYPE_U8, &dir,
+					  err) < 0)
 			return -1;
 
 		if (dir != IP_CT_DIR_ORIGINAL && dir != IP_CT_DIR_REPLY)
@@ -225,7 +227,8 @@ err:
 }
 
 
-static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				      struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_ct *ct = nft_expr_data(e);
@@ -234,7 +237,7 @@ static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree
 	int key;
 	uint8_t dir;
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
@@ -242,7 +245,7 @@ static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree
 	e->flags |= (1 << NFT_EXPR_CT_DREG);
 
 	key_str = nft_mxml_str_parse(tree, "key", MXML_DESCEND_FIRST,
-				     NFT_XML_MAND);
+				     NFT_XML_MAND, err);
 	if (key_str == NULL)
 		return -1;
 
@@ -254,7 +257,7 @@ static int nft_rule_expr_ct_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree
 	e->flags |= (1 << NFT_EXPR_CT_KEY);
 
 	if (nft_mxml_num_parse(tree, "dir", MXML_DESCEND_FIRST, BASE_DEC,
-			       &dir, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+			       &dir, NFT_TYPE_U8, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	if (dir != IP_CT_DIR_ORIGINAL && dir != IP_CT_DIR_REPLY)
diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c
index 76231af..e487bc7 100644
--- a/src/expr/data_reg.c
+++ b/src/expr/data_reg.c
@@ -27,12 +27,13 @@
 #include "internal.h"
 
 #ifdef JSON_PARSING
-static int nft_data_reg_verdict_json_parse(union nft_data_reg *reg, json_t *data)
+static int nft_data_reg_verdict_json_parse(union nft_data_reg *reg, json_t *data,
+					   struct nft_parse_err *err)
 {
 	int verdict;
 	const char *verdict_str;
 
-	verdict_str = nft_jansson_parse_str(data, "verdict");
+	verdict_str = nft_jansson_parse_str(data, "verdict", err);
 	if (verdict_str == NULL)
 		return -1;
 
@@ -45,9 +46,10 @@ static int nft_data_reg_verdict_json_parse(union nft_data_reg *reg, json_t *data
 	return 0;
 }
 
-static int nft_data_reg_chain_json_parse(union nft_data_reg *reg, json_t *data)
+static int nft_data_reg_chain_json_parse(union nft_data_reg *reg, json_t *data,
+					 struct nft_parse_err *err)
 {
-	reg->chain = strdup(nft_jansson_parse_str(data, "chain"));
+	reg->chain = strdup(nft_jansson_parse_str(data, "chain", err));
 	if (reg->chain == NULL) {
 		return -1;
 	}
@@ -55,19 +57,20 @@ static int nft_data_reg_chain_json_parse(union nft_data_reg *reg, json_t *data)
 	return 0;
 }
 
-static int nft_data_reg_value_json_parse(union nft_data_reg *reg, json_t *data)
+static int nft_data_reg_value_json_parse(union nft_data_reg *reg, json_t *data,
+					 struct nft_parse_err *err)
 {
 	int i;
 	char node_name[6];
 
-	if (nft_jansson_parse_val(data, "len", NFT_TYPE_U8, &reg->len) < 0)
+	if (nft_jansson_parse_val(data, "len", NFT_TYPE_U8, &reg->len, err) < 0)
 			return -1;
 
 	for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
 		sprintf(node_name, "data%d", i);
 
 		if (nft_jansson_str2num(data, node_name, BASE_HEX,
-				        &reg->val[i], NFT_TYPE_U32) != 0)
+					&reg->val[i], NFT_TYPE_U32, err) != 0)
 			return -1;
 	}
 
@@ -75,23 +78,24 @@ static int nft_data_reg_value_json_parse(union nft_data_reg *reg, json_t *data)
 }
 #endif
 
-int nft_data_reg_json_parse(union nft_data_reg *reg, json_t *data)
+int nft_data_reg_json_parse(union nft_data_reg *reg, json_t *data,
+			    struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 
 	const char *type;
 
-	type = nft_jansson_parse_str(data, "type");
+	type = nft_jansson_parse_str(data, "type", err);
 	if (type == NULL)
 		return -1;
 
 	/* Select what type of parsing is needed */
 	if (strcmp(type, "value") == 0) {
-		return nft_data_reg_value_json_parse(reg, data);
+		return nft_data_reg_value_json_parse(reg, data, err);
 	} else if (strcmp(type, "verdict") == 0) {
-		return nft_data_reg_verdict_json_parse(reg, data);
+		return nft_data_reg_verdict_json_parse(reg, data, err);
 	} else if (strcmp(type, "chain") == 0) {
-		return nft_data_reg_chain_json_parse(reg, data);
+		return nft_data_reg_chain_json_parse(reg, data, err);
 	}
 
 	return 0;
@@ -103,13 +107,14 @@ int nft_data_reg_json_parse(union nft_data_reg *reg, json_t *data)
 
 #ifdef XML_PARSING
 static int nft_data_reg_verdict_xml_parse(union nft_data_reg *reg,
-					  mxml_node_t *tree)
+					  mxml_node_t *tree,
+					  struct nft_parse_err *err)
 {
 	int verdict;
 	const char *verdict_str;
 
 	verdict_str = nft_mxml_str_parse(tree, "verdict", MXML_DESCEND_FIRST,
-					 NFT_XML_MAND);
+					 NFT_XML_MAND, err);
 	if (verdict_str == NULL)
 		return DATA_NONE;
 
@@ -123,12 +128,13 @@ static int nft_data_reg_verdict_xml_parse(union nft_data_reg *reg,
 }
 
 static int nft_data_reg_chain_xml_parse(union nft_data_reg *reg,
-					mxml_node_t *tree)
+					mxml_node_t *tree,
+					struct nft_parse_err *err)
 {
 	const char *chain;
 
 	chain = nft_mxml_str_parse(tree, "chain", MXML_DESCEND_FIRST,
-				   NFT_XML_MAND);
+				   NFT_XML_MAND, err);
 	if (chain == NULL)
 		return DATA_NONE;
 
@@ -140,7 +146,8 @@ static int nft_data_reg_chain_xml_parse(union nft_data_reg *reg,
 }
 
 static int nft_data_reg_value_xml_parse(union nft_data_reg *reg,
-					mxml_node_t *tree)
+					mxml_node_t *tree,
+					struct nft_parse_err *err)
 {
 	int i;
 	char node_name[6];
@@ -156,7 +163,7 @@ static int nft_data_reg_value_xml_parse(union nft_data_reg *reg,
 	*/
 
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
-			       &reg->len, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+			       &reg->len, NFT_TYPE_U8, NFT_XML_MAND, err) != 0)
 		return DATA_NONE;
 
 	/* Get and set <dataN> */
@@ -165,7 +172,7 @@ static int nft_data_reg_value_xml_parse(union nft_data_reg *reg,
 
 		if (nft_mxml_num_parse(tree, node_name, MXML_DESCEND_FIRST,
 				       BASE_HEX, &reg->val[i], NFT_TYPE_U32,
-				       NFT_XML_MAND) != 0)
+				       NFT_XML_MAND, err) != 0)
 			return DATA_NONE;
 	}
 
@@ -173,7 +180,8 @@ static int nft_data_reg_value_xml_parse(union nft_data_reg *reg,
 }
 #endif
 
-int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree)
+int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree,
+			   struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	const char *type;
@@ -194,11 +202,11 @@ int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree)
 	}
 
 	if (strcmp(type, "value") == 0)
-		return nft_data_reg_value_xml_parse(reg, node);
+		return nft_data_reg_value_xml_parse(reg, node, err);
 	else if (strcmp(type, "verdict") == 0)
-		return nft_data_reg_verdict_xml_parse(reg, node);
+		return nft_data_reg_verdict_xml_parse(reg, node, err);
 	else if (strcmp(type, "chain") == 0)
-		return nft_data_reg_chain_xml_parse(reg, node);
+		return nft_data_reg_chain_xml_parse(reg, node, err);
 
 	return DATA_NONE;
 #else
diff --git a/src/expr/data_reg.h b/src/expr/data_reg.h
index 8a6a235..5258051 100644
--- a/src/expr/data_reg.h
+++ b/src/expr/data_reg.h
@@ -29,8 +29,10 @@ union nft_data_reg {
 
 int nft_data_reg_snprintf(char *buf, size_t size, union nft_data_reg *reg,
                         uint32_t output_format, uint32_t flags, int reg_type);
-int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree);
+int nft_data_reg_xml_parse(union nft_data_reg *reg, mxml_node_t *tree,
+			   struct nft_parse_err *err);
 int nft_parse_data(union nft_data_reg *data, struct nlattr *attr, int *type);
-int nft_data_reg_json_parse(union nft_data_reg *reg, json_t *data);
+int nft_data_reg_json_parse(union nft_data_reg *reg, json_t *data,
+			    struct nft_parse_err *err);
 
 #endif
diff --git a/src/expr/exthdr.c b/src/expr/exthdr.c
index 6841ac1..813830b 100644
--- a/src/expr/exthdr.c
+++ b/src/expr/exthdr.c
@@ -193,19 +193,20 @@ static inline int str2exthdr_type(const char *str)
 }
 
 static int
-nft_rule_expr_exthdr_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_exthdr_json_parse(struct nft_rule_expr *e, json_t *root,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *exthdr_type;
 	uint32_t uval32;
 	int type;
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_DREG, uval32);
 
-	exthdr_type = nft_jansson_parse_str(root, "exthdr_type");
+	exthdr_type = nft_jansson_parse_str(root, "exthdr_type", err);
 	if (exthdr_type == NULL)
 		return -1;
 
@@ -215,12 +216,12 @@ nft_rule_expr_exthdr_json_parse(struct nft_rule_expr *e, json_t *root)
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_TYPE, type);
 
-	if (nft_jansson_parse_val(root, "offset", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "offset", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_OFFSET, uval32);
 
-	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_LEN, uval32);
@@ -233,7 +234,8 @@ nft_rule_expr_exthdr_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_exthdr *exthdr = nft_expr_data(e);
@@ -241,7 +243,7 @@ nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	int32_t reg;
 	int type;
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
@@ -249,7 +251,7 @@ nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	e->flags |= (1 << NFT_EXPR_EXTHDR_DREG);
 
 	exthdr_type = nft_mxml_str_parse(tree, "exthdr_type",
-					 MXML_DESCEND_FIRST, NFT_XML_MAND);
+					 MXML_DESCEND_FIRST, NFT_XML_MAND, err);
 	if (exthdr_type == NULL)
 		return -1;
 
@@ -263,14 +265,15 @@ nft_rule_expr_exthdr_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	/* Get and set <offset> */
 	if (nft_mxml_num_parse(tree, "offset", MXML_DESCEND_FIRST, BASE_DEC,
 			       &exthdr->offset, NFT_TYPE_U32,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_EXTHDR_OFFSET);
 
 	/* Get and set <len> */
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
-			       &exthdr->len, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &exthdr->len, NFT_TYPE_U32, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_EXTHDR_LEN);
diff --git a/src/expr/immediate.c b/src/expr/immediate.c
index a96d3de..3ae4082 100644
--- a/src/expr/immediate.c
+++ b/src/expr/immediate.c
@@ -178,20 +178,21 @@ nft_rule_expr_immediate_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
-nft_rule_expr_immediate_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_immediate_json_parse(struct nft_rule_expr *e, json_t *root,
+				   struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	struct nft_expr_immediate *imm = nft_expr_data(e);
 	int datareg_type;
 	uint32_t reg;
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, reg);
 
 	datareg_type = nft_jansson_data_reg_parse(root, "immediatedata",
-						  &imm->data);
+						  &imm->data, err);
 	if (datareg_type < 0)
 		return -1;
 
@@ -217,14 +218,15 @@ nft_rule_expr_immediate_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				  struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_immediate *imm = nft_expr_data(e);
 	int datareg_type;
 	int32_t reg;
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
@@ -232,7 +234,7 @@ nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	e->flags |= (1 << NFT_EXPR_IMM_DREG);
 
 	datareg_type = nft_mxml_data_reg_parse(tree, "immediatedata",
-					       &imm->data, NFT_XML_MAND);
+					       &imm->data, NFT_XML_MAND, err);
 	switch (datareg_type) {
 	case DATA_VALUE:
 		e->flags |= (1 << NFT_EXPR_IMM_DATA);
diff --git a/src/expr/limit.c b/src/expr/limit.c
index 4854a77..e6b0492 100644
--- a/src/expr/limit.c
+++ b/src/expr/limit.c
@@ -118,17 +118,18 @@ nft_rule_expr_limit_parse(struct nft_rule_expr *e, struct nlattr *attr)
 	return 0;
 }
 
-static int nft_rule_expr_limit_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_limit_json_parse(struct nft_rule_expr *e, json_t *root,
+					  struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	uint64_t uval64;
 
-	if (nft_jansson_parse_val(root, "rate", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "rate", NFT_TYPE_U64, &uval64, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u64(e, NFT_EXPR_LIMIT_RATE, uval64);
 
-	if (nft_jansson_parse_val(root, "unit", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "unit", NFT_TYPE_U64, &uval64, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u64(e, NFT_EXPR_LIMIT_UNIT, uval64);
@@ -140,19 +141,23 @@ static int nft_rule_expr_limit_json_parse(struct nft_rule_expr *e, json_t *root)
 #endif
 }
 
-static int nft_rule_expr_limit_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_limit_xml_parse(struct nft_rule_expr *e,
+					 mxml_node_t *tree,
+					 struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_limit *limit = nft_expr_data(e);
 
 	if (nft_mxml_num_parse(tree, "rate", MXML_DESCEND_FIRST, BASE_DEC,
-			       &limit->rate, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &limit->rate, NFT_TYPE_U64, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_LIMIT_RATE);
 
 	if (nft_mxml_num_parse(tree, "unit", MXML_DESCEND_FIRST, BASE_DEC,
-			       &limit->unit, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &limit->unit, NFT_TYPE_U64, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_LIMIT_UNIT);
diff --git a/src/expr/log.c b/src/expr/log.c
index 76657a9..c62a8b4 100644
--- a/src/expr/log.c
+++ b/src/expr/log.c
@@ -160,31 +160,34 @@ nft_rule_expr_log_parse(struct nft_rule_expr *e, struct nlattr *attr)
 	return 0;
 }
 
-static int nft_rule_expr_log_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_log_json_parse(struct nft_rule_expr *e, json_t *root,
+					struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *prefix;
 	uint32_t snaplen;
 	uint16_t uval16;
 
-	prefix = nft_jansson_parse_str(root, "prefix");
+	prefix = nft_jansson_parse_str(root, "prefix", err);
 	if (prefix == NULL)
 		return -1;
 
 	nft_rule_expr_set_str(e, NFT_EXPR_LOG_PREFIX, prefix);
 
-	if (nft_jansson_parse_val(root, "group", NFT_TYPE_U16, &uval16) < 0)
+	if (nft_jansson_parse_val(root, "group", NFT_TYPE_U16, &uval16,
+				  err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u16(e, NFT_EXPR_LOG_GROUP, uval16);
 
-	if (nft_jansson_parse_val(root, "snaplen", NFT_TYPE_U32, &snaplen) < 0)
+	if (nft_jansson_parse_val(root, "snaplen", NFT_TYPE_U32, &snaplen,
+				  err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_LOG_SNAPLEN, snaplen);
 
 	if (nft_jansson_parse_val(root, "qthreshold", NFT_TYPE_U16,
-				  &uval16) < 0)
+				  &uval16, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u16(e, NFT_EXPR_LOG_QTHRESHOLD, uval16);
@@ -196,14 +199,16 @@ static int nft_rule_expr_log_json_parse(struct nft_rule_expr *e, json_t *root)
 #endif
 }
 
-static int nft_rule_expr_log_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_log_xml_parse(struct nft_rule_expr *e,
+				       mxml_node_t *tree,
+				       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_log *log = nft_expr_data(e);
 	const char *prefix;
 
 	prefix = nft_mxml_str_parse(tree, "prefix", MXML_DESCEND_FIRST,
-				    NFT_XML_MAND);
+				    NFT_XML_MAND, err);
 	if (prefix == NULL)
 		return -1;
 
@@ -211,20 +216,22 @@ static int nft_rule_expr_log_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	e->flags |= (1 << NFT_EXPR_LOG_PREFIX);
 
 	if (nft_mxml_num_parse(tree, "group", MXML_DESCEND_FIRST, BASE_DEC,
-			       &log->group, NFT_TYPE_U16, NFT_XML_MAND) != 0)
+			       &log->group, NFT_TYPE_U16, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_LOG_GROUP);
 
 	if (nft_mxml_num_parse(tree, "snaplen", MXML_DESCEND_FIRST, BASE_DEC,
-			       &log->snaplen, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &log->snaplen, NFT_TYPE_U32, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_LOG_SNAPLEN);
 
 	if (nft_mxml_num_parse(tree, "qthreshold", MXML_DESCEND_FIRST,
 			       BASE_DEC, &log->qthreshold,
-			       NFT_TYPE_U16, NFT_XML_MAND) != 0)
+			       NFT_TYPE_U16, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_LOG_QTHRESHOLD);
diff --git a/src/expr/lookup.c b/src/expr/lookup.c
index 4e91cfb..b0aadf2 100644
--- a/src/expr/lookup.c
+++ b/src/expr/lookup.c
@@ -143,24 +143,25 @@ nft_rule_expr_lookup_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
-nft_rule_expr_lookup_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_lookup_json_parse(struct nft_rule_expr *e, json_t *root,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *set_name;
 	int32_t reg;
 
-	set_name = nft_jansson_parse_str(root, "set");
+	set_name = nft_jansson_parse_str(root, "set", err);
 	if (set_name == NULL)
 		return -1;
 
 	nft_rule_expr_set_str(e, NFT_EXPR_LOOKUP_SET, set_name);
 
-	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_SREG, reg);
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_DREG, reg);
@@ -173,7 +174,8 @@ nft_rule_expr_lookup_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_lookup *lookup = nft_expr_data(e);
@@ -181,7 +183,7 @@ nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	int32_t reg;
 
 	set_name = nft_mxml_str_parse(tree, "set", MXML_DESCEND_FIRST,
-				      NFT_XML_MAND);
+				      NFT_XML_MAND, err);
 	if (set_name == NULL)
 		return -1;
 
@@ -189,14 +191,14 @@ nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	lookup->set_name[IFNAMSIZ-1] = '\0';
 	e->flags |= (1 << NFT_EXPR_LOOKUP_SET);
 
-	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "sreg", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
 	lookup->sreg = reg;
 	e->flags |= (1 << NFT_EXPR_LOOKUP_SREG);
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
diff --git a/src/expr/match.c b/src/expr/match.c
index c7863b8..5487050 100644
--- a/src/expr/match.c
+++ b/src/expr/match.c
@@ -170,12 +170,13 @@ static int nft_rule_expr_match_parse(struct nft_rule_expr *e, struct nlattr *att
 	return 0;
 }
 
-static int nft_rule_expr_match_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_match_json_parse(struct nft_rule_expr *e, json_t *root,
+					  struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *name;
 
-	name = nft_jansson_parse_str(root, "name");
+	name = nft_jansson_parse_str(root, "name", err);
 	if (name == NULL)
 		return -1;
 
@@ -189,14 +190,15 @@ static int nft_rule_expr_match_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 
-static int nft_rule_expr_match_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_match_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+					 struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_match *mt = nft_expr_data(e);
 	const char *name;
 
 	name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
-				  NFT_XML_MAND);
+				  NFT_XML_MAND, err);
 	if (name == NULL)
 		return -1;
 
diff --git a/src/expr/meta.c b/src/expr/meta.c
index 88d2908..3c5fd77 100644
--- a/src/expr/meta.c
+++ b/src/expr/meta.c
@@ -160,19 +160,20 @@ static inline int str2meta_key(const char *str)
 	return -1;
 }
 
-static int nft_rule_expr_meta_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_meta_json_parse(struct nft_rule_expr *e, json_t *root,
+					 struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *key_str;
 	uint32_t reg;
 	int key;
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
                 return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_META_DREG, reg);
 
-	key_str = nft_jansson_parse_str(root, "key");
+	key_str = nft_jansson_parse_str(root, "key", err);
 	if (key_str == NULL)
 		return -1;
 
@@ -190,7 +191,8 @@ static int nft_rule_expr_meta_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 
-static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+					struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_meta *meta = nft_expr_data(e);
@@ -198,7 +200,7 @@ static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tr
 	int32_t reg;
 	int key;
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
                 return -1;
 
@@ -206,7 +208,7 @@ static int nft_rule_expr_meta_xml_parse(struct nft_rule_expr *e, mxml_node_t *tr
 	e->flags |= (1 << NFT_EXPR_META_DREG);
 
 	key_str = nft_mxml_str_parse(tree, "key", MXML_DESCEND_FIRST,
-				     NFT_XML_MAND);
+				     NFT_XML_MAND, err);
 	if (key_str == NULL)
 		return -1;
 
diff --git a/src/expr/nat.c b/src/expr/nat.c
index 30b02ec..34a977a 100644
--- a/src/expr/nat.c
+++ b/src/expr/nat.c
@@ -196,14 +196,15 @@ static inline int nft_str2nat(const char *nat)
 	}
 }
 
-static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root)
+static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root,
+					struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *nat_type, *family_str;
 	uint32_t reg;
 	int val32;
 
-	nat_type = nft_jansson_parse_str(root, "nat_type");
+	nat_type = nft_jansson_parse_str(root, "nat_type", err);
 	if (nat_type == NULL)
 		return -1;
 
@@ -213,7 +214,7 @@ static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root)
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, val32);
 
-	family_str = nft_jansson_parse_str(root, "family");
+	family_str = nft_jansson_parse_str(root, "family", err);
 	if (family_str == NULL)
 		return -1;
 
@@ -224,25 +225,25 @@ static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root)
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, val32);
 
 	if (nft_jansson_parse_reg(root, "sreg_addr_min", NFT_TYPE_U32,
-				  &reg) < 0)
+				  &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, reg);
 
 	if (nft_jansson_parse_reg(root, "sreg_addr_max", NFT_TYPE_U32,
-				  &reg) < 0)
+				  &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, reg);
 
 	if (nft_jansson_parse_reg(root, "sreg_proto_min", NFT_TYPE_U32,
-				  &reg) < 0)
+				  &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MIN, reg);
 
 	if (nft_jansson_parse_reg(root, "sreg_proto_max", NFT_TYPE_U32,
-				  &reg) < 0)
+				  &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MAX, reg);
@@ -254,7 +255,8 @@ static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root)
 #endif
 }
 
-static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_nat *nat = nft_expr_data(e);
@@ -263,7 +265,7 @@ static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	int family, nat_type_value;
 
 	nat_type = nft_mxml_str_parse(tree, "type", MXML_DESCEND_FIRST,
-				      NFT_XML_MAND);
+				      NFT_XML_MAND, err);
 	if (nat_type == NULL)
 		return -1;
 
@@ -275,7 +277,7 @@ static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	e->flags |= (1 << NFT_EXPR_NAT_TYPE);
 
 	family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
-				       NFT_XML_MAND);
+				       NFT_XML_MAND, err);
 	if (family < 0) {
 		mxmlDelete(tree);
 		return -1;
@@ -284,28 +286,28 @@ static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tre
 	nat->family = family;
 	e->flags |= (1 << NFT_EXPR_NAT_FAMILY);
 
-	reg = nft_mxml_reg_parse(tree, "sreg_addr_min", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "sreg_addr_min", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
 	nat->sreg_addr_min = reg;
 	e->flags |= (1 << NFT_EXPR_NAT_REG_ADDR_MIN);
 
-	reg = nft_mxml_reg_parse(tree, "sreg_addr_max", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "sreg_addr_max", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
 	nat->sreg_addr_max = reg;
 	e->flags |= (1 << NFT_EXPR_NAT_REG_ADDR_MAX);
 
-	reg = nft_mxml_reg_parse(tree, "sreg_proto_min", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "sreg_proto_min", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
 	nat->sreg_proto_min = reg;
 	e->flags |= (1 << NFT_EXPR_NAT_REG_PROTO_MIN);
 
-	reg = nft_mxml_reg_parse(tree, "sreg_proto_max", MXML_DESCEND);
+	reg = nft_mxml_reg_parse(tree, "sreg_proto_max", MXML_DESCEND, err);
 	if (reg < 0)
 		return -1;
 
diff --git a/src/expr/payload.c b/src/expr/payload.c
index fc32ff2..911bb01 100644
--- a/src/expr/payload.c
+++ b/src/expr/payload.c
@@ -194,19 +194,20 @@ static inline int nft_str2base(const char *base)
 }
 
 static int
-nft_rule_expr_payload_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_payload_json_parse(struct nft_rule_expr *e, json_t *root,
+				 struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *base_str;
 	uint32_t reg, uval32;
 	int base;
 
-	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg) < 0)
+	if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, reg);
 
-	base_str = nft_jansson_parse_str(root, "base");
+	base_str = nft_jansson_parse_str(root, "base", err);
 	if (base_str == NULL)
 		return -1;
 
@@ -216,12 +217,13 @@ nft_rule_expr_payload_json_parse(struct nft_rule_expr *e, json_t *root)
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, base);
 
-	if (nft_jansson_parse_val(root, "offset", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "offset", NFT_TYPE_U32, &uval32,
+				  err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, uval32);
 
-	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, uval32);
@@ -234,14 +236,15 @@ nft_rule_expr_payload_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+				struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_payload *payload = nft_expr_data(e);
 	const char *base_str;
 	int32_t reg, base;
 
-	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST);
+	reg = nft_mxml_reg_parse(tree, "dreg", MXML_DESCEND_FIRST, err);
 	if (reg < 0)
 		return -1;
 
@@ -249,7 +252,7 @@ nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 	e->flags |= (1 << NFT_EXPR_PAYLOAD_DREG);
 
 	base_str = nft_mxml_str_parse(tree, "base", MXML_DESCEND_FIRST,
-				      NFT_XML_MAND);
+				      NFT_XML_MAND, err);
 	if (base_str == NULL)
 		return -1;
 
@@ -262,13 +265,14 @@ nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
 
 	if (nft_mxml_num_parse(tree, "offset", MXML_DESCEND_FIRST, BASE_DEC,
 			       &payload->offset, NFT_TYPE_U8,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_PAYLOAD_OFFSET);
 
 	if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
-			       &payload->len, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+			       &payload->len, NFT_TYPE_U8,
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_PAYLOAD_LEN);
diff --git a/src/expr/reject.c b/src/expr/reject.c
index 848f004..c06b070 100644
--- a/src/expr/reject.c
+++ b/src/expr/reject.c
@@ -122,18 +122,19 @@ nft_rule_expr_reject_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
-nft_rule_expr_reject_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_reject_json_parse(struct nft_rule_expr *e, json_t *root,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	uint32_t type;
 	uint16_t code;
 
-	if (nft_jansson_parse_val(root, "type", NFT_TYPE_U32, &type) < 0)
+	if (nft_jansson_parse_val(root, "type", NFT_TYPE_U32, &type, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u32(e, NFT_EXPR_REJECT_TYPE, type);
 
-	if (nft_jansson_parse_val(root, "code", NFT_TYPE_U8, &code) < 0)
+	if (nft_jansson_parse_val(root, "code", NFT_TYPE_U8, &code, err) < 0)
 		return -1;
 
 	nft_rule_expr_set_u8(e, NFT_EXPR_REJECT_CODE, code);
@@ -146,19 +147,22 @@ nft_rule_expr_reject_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_reject_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_reject_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_reject *reject = nft_expr_data(e);
 
 	if (nft_mxml_num_parse(tree, "type", MXML_DESCEND_FIRST, BASE_DEC,
-			       &reject->type, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &reject->type, NFT_TYPE_U32, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_REJECT_TYPE);
 
 	if (nft_mxml_num_parse(tree, "code", MXML_DESCEND_FIRST, BASE_DEC,
-			       &reject->icmp_code, NFT_TYPE_U8, NFT_XML_MAND) != 0)
+			       &reject->icmp_code, NFT_TYPE_U8, NFT_XML_MAND,
+			       err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_EXPR_REJECT_CODE);
diff --git a/src/expr/target.c b/src/expr/target.c
index 23dff3a..071fb07 100644
--- a/src/expr/target.c
+++ b/src/expr/target.c
@@ -171,12 +171,13 @@ static int nft_rule_expr_target_parse(struct nft_rule_expr *e, struct nlattr *at
 }
 
 static int
-nft_rule_expr_target_json_parse(struct nft_rule_expr *e, json_t *root)
+nft_rule_expr_target_json_parse(struct nft_rule_expr *e, json_t *root,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	const char *name;
 
-	name = nft_jansson_parse_str(root, "name");
+	name = nft_jansson_parse_str(root, "name", err);
 	if (name == NULL)
 		return -1;
 
@@ -190,14 +191,15 @@ nft_rule_expr_target_json_parse(struct nft_rule_expr *e, json_t *root)
 }
 
 static int
-nft_rule_expr_target_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+nft_rule_expr_target_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	struct nft_expr_target *tg = nft_expr_data(e);
 	const char *name;
 
 	name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
-				  NFT_XML_MAND);
+				  NFT_XML_MAND, err);
 	if (name == NULL)
 		return -1;
 
diff --git a/src/expr_ops.h b/src/expr_ops.h
index 26e0b82..b06f575 100644
--- a/src/expr_ops.h
+++ b/src/expr_ops.h
@@ -29,8 +29,10 @@ struct expr_ops {
 	int 	(*parse)(struct nft_rule_expr *e, struct nlattr *attr);
 	void	(*build)(struct nlmsghdr *nlh, struct nft_rule_expr *e);
 	int	(*snprintf)(char *buf, size_t len, uint32_t type, uint32_t flags, struct nft_rule_expr *e);
-	int	(*xml_parse)(struct nft_rule_expr *e, mxml_node_t *tree);
-	int	(*json_parse)(struct nft_rule_expr *e, json_t *data);
+	int	(*xml_parse)(struct nft_rule_expr *e, mxml_node_t *tree,
+			     struct nft_parse_err *err);
+	int	(*json_parse)(struct nft_rule_expr *e, json_t *data,
+			      struct nft_parse_err *err);
 };
 
 void nft_expr_ops_register(struct expr_ops *ops);
diff --git a/src/internal.h b/src/internal.h
index f975ad1..9ef505f 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -13,6 +13,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <libnftables/common.h>
 
 #define BASE_DEC 10
 #define BASE_HEX 16
@@ -30,59 +31,94 @@ enum nft_type {
 	NFT_TYPE_S64,
 };
 
+struct nft_parse_err {
+	int line;
+	int column;
+	int error;
+	const char *node_name;
+};
+
 #ifdef XML_PARSING
 #include <mxml.h>
 #define NFT_XML_MAND 0
 #define NFT_XML_OPT (1 << 0)
-mxml_node_t *nft_mxml_build_tree(const char *xml, const char *treename);
-struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node);
-int nft_mxml_reg_parse(mxml_node_t *tree, const char *reg_name, uint32_t flags);
+mxml_node_t *nft_mxml_build_tree(const char *xml, const char *treename,
+				 struct nft_parse_err *err);
+struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node,
+					  struct nft_parse_err *err);
+int nft_mxml_reg_parse(mxml_node_t *tree, const char *reg_name, uint32_t flags,
+		       struct nft_parse_err *err);
 union nft_data_reg;
-int nft_mxml_data_reg_parse(mxml_node_t *tree, const char *node_name, union nft_data_reg *data_reg, uint16_t flags);
-int nft_mxml_num_parse(mxml_node_t *tree, const char *node_name, uint32_t mxml_flags, int base, void *number, enum nft_type type, uint16_t flags);
-const char *nft_mxml_str_parse(mxml_node_t *tree, const char *node_name, uint32_t mxml_flags, uint16_t flags);
-int nft_mxml_family_parse(mxml_node_t *tree, const char *node_name, uint32_t mxml_flags, uint16_t flags);
+int nft_mxml_data_reg_parse(mxml_node_t *tree, const char *node_name,
+			    union nft_data_reg *data_reg, uint16_t flags,
+			    struct nft_parse_err *err);
+int nft_mxml_num_parse(mxml_node_t *tree, const char *node_name,
+		       uint32_t mxml_flags, int base, void *number,
+		       enum nft_type type, uint16_t flags,
+		       struct nft_parse_err *err);
+const char *nft_mxml_str_parse(mxml_node_t *tree, const char *node_name,
+			       uint32_t mxml_flags, uint16_t flags,
+			       struct nft_parse_err *err);
+int nft_mxml_family_parse(mxml_node_t *tree, const char *node_name,
+			  uint32_t mxml_flags, uint16_t flags,
+			  struct nft_parse_err *err);
 
 struct nft_set_elem;
-int nft_mxml_set_elem_parse(mxml_node_t *node, struct nft_set_elem *e);
+int nft_mxml_set_elem_parse(mxml_node_t *node, struct nft_set_elem *e,
+			    struct nft_parse_err *err);
 struct nft_table;
-int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t);
+int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t,
+			 struct nft_parse_err *err);
 struct nft_chain;
-int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c);
+int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c,
+			 struct nft_parse_err *err);
 struct nft_rule;
-int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r);
+int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r,
+			struct nft_parse_err *err);
 struct nft_set;
-int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s);
+int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s,
+		       struct nft_parse_err *err);
 #endif
 
 #ifdef JSON_PARSING
 #include <jansson.h>
+
 int nft_jansson_parse_val(json_t *root, const char *node_name, int type,
-			  void *out);
-const char *nft_jansson_parse_str(json_t *root, const char *node_name);
+			  void *out, struct nft_parse_err *err);
+const char *nft_jansson_parse_str(json_t *root, const char *node_name,
+				  struct nft_parse_err *err);
 bool nft_jansson_node_exist(json_t *root, const char *node_name);
-json_t *nft_jansson_create_root(const char *json, json_error_t *err);
-json_t *nft_jansson_get_node(json_t *root, const char *node_name);
+json_t *nft_jansson_create_root(const char *json, json_error_t *error,
+				struct nft_parse_err *err);
+json_t *nft_jansson_get_node(json_t *root, const char *node_name,
+			     struct nft_parse_err *err);
 void nft_jansson_free_root(json_t *root);
-int nft_jansson_parse_family(json_t *root, void *out);
-int nft_jansson_str2num(json_t *root, const char *node_name, int base,
-			void *out, enum nft_type type);
+int nft_jansson_parse_family(json_t *root, void *out, struct nft_parse_err *err);
+int nft_jansson_str2num(json_t *root, const char *node_name, int base, void *out,
+			enum nft_type type, struct nft_parse_err *err);
 int nft_jansson_parse_reg(json_t *root, const char *node_name, int type,
-			  void *out);
-struct nft_rule_expr *nft_jansson_expr_parse(json_t *root);
+			  void *out, struct nft_parse_err *err);
+struct nft_rule_expr *nft_jansson_expr_parse(json_t *root,
+					     struct nft_parse_err *err);
 union nft_data_reg;
 int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
-			       union nft_data_reg *data_reg);
+			       union nft_data_reg *data_reg,
+			       struct nft_parse_err *err);
 struct nft_set_elem;
-int nft_set_elem_json_parse(struct nft_set_elem *e, json_t *root);
+int nft_set_elem_json_parse(struct nft_set_elem *e, json_t *root,
+			    struct nft_parse_err *err);
 struct nft_table;
-int nft_jansson_parse_table(struct nft_table *t, json_t *tree);
+int nft_jansson_parse_table(struct nft_table *t, json_t *tree,
+			    struct nft_parse_err *err);
 struct nft_chain;
-int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree);
+int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree,
+			    struct nft_parse_err *err);
 struct nft_rule;
-int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree);
+int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree,
+			   struct nft_parse_err *err);
 struct nft_set;
-int nft_jansson_parse_set(struct nft_set *s, json_t *tree);
+int nft_jansson_parse_set(struct nft_set *s, json_t *tree,
+			  struct nft_parse_err *err);
 #endif
 
 const char *nft_family2str(uint32_t family);
diff --git a/src/jansson.c b/src/jansson.c
index 539f9ab..54a56b9 100644
--- a/src/jansson.c
+++ b/src/jansson.c
@@ -24,17 +24,21 @@
 #ifdef JSON_PARSING
 
 static int nft_jansson_load_int_node(json_t *root, const char *node_name,
-				      json_int_t *val)
+				      json_int_t *val, struct nft_parse_err *err)
 {
 	json_t *node;
 
 	node = json_object_get(root, node_name);
 	if (node == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = node_name;
 		errno = EINVAL;
 		return -1;
 	}
 
 	if (!json_is_integer(node)) {
+		err->error = NFT_PARSE_EBADTYPE;
+		err->node_name = node_name;
 		errno = ERANGE;
 		return -1;
 	}
@@ -43,27 +47,35 @@ static int nft_jansson_load_int_node(json_t *root, const char *node_name,
 	return 0;
 }
 
-const char *nft_jansson_parse_str(json_t *root, const char *node_name)
+const char *nft_jansson_parse_str(json_t *root, const char *node_name,
+				  struct nft_parse_err *err)
 {
 	json_t *node;
 	const char *val;
 
 	node = json_object_get(root, node_name);
 	if (node == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = node_name;
 		errno = EINVAL;
 		return NULL;
 	}
+
 	val = json_string_value(node);
+	if (val == NULL) {
+		err->error = NFT_PARSE_EBADTYPE;
+		err->node_name = node_name;
+	}
 
 	return val;
 }
 
 int nft_jansson_parse_val(json_t *root, const char *node_name, int type,
-			  void *out)
+			  void *out, struct nft_parse_err *err)
 {
 	json_int_t val;
 
-	if (nft_jansson_load_int_node(root, node_name, &val) == -1)
+	if (nft_jansson_load_int_node(root, node_name, &val, err) == -1)
 		return -1;
 
 	if (nft_get_value(type, &val, out) == -1)
@@ -77,12 +89,17 @@ bool nft_jansson_node_exist(json_t *root, const char *node_name)
 	return json_object_get(root, node_name) != NULL;
 }
 
-json_t *nft_jansson_create_root(const char *json, json_error_t *err)
+json_t *nft_jansson_create_root(const char *json, json_error_t *error,
+				struct nft_parse_err *err)
 {
 	json_t *root;
 
-	root = json_loadb(json, strlen(json), 0, err);
+	root = json_loadb(json, strlen(json), 0, error);
 	if (root == NULL) {
+		err->error = NFT_PARSE_EBADINPUT;
+		err->line = error->line;
+		err->column = error->column;
+		err->node_name = error->source;
 		errno = EINVAL;
 		return NULL;
 	}
@@ -90,12 +107,15 @@ json_t *nft_jansson_create_root(const char *json, json_error_t *err)
 	return root;
 }
 
-json_t *nft_jansson_get_node(json_t *root, const char *node_name)
+json_t *nft_jansson_get_node(json_t *root, const char *node_name,
+			     struct nft_parse_err *err)
 {
 	json_t *node;
 
 	node = json_object_get(root, node_name);
 	if (node == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = node_name;
 		errno = EINVAL;
 		return NULL;
 	}
@@ -108,17 +128,18 @@ void nft_jansson_free_root(json_t *root)
 	json_decref(root);
 }
 
-int nft_jansson_parse_family(json_t *root, void *out)
+int nft_jansson_parse_family(json_t *root, void *out, struct nft_parse_err *err)
 {
 	const char *str;
 	int family;
 
-	str = nft_jansson_parse_str(root, "family");
+	str = nft_jansson_parse_str(root, "family", err);
 	if (str == NULL)
 		return -1;
 
 	family = nft_str2family(str);
 	if (family < 0) {
+		err->node_name = "family";
 		errno = EINVAL;
 		return -1;
 	}
@@ -128,9 +149,9 @@ int nft_jansson_parse_family(json_t *root, void *out)
 }
 
 int nft_jansson_parse_reg(json_t *root, const char *node_name, int type,
-			  void *out)
+			  void *out, struct nft_parse_err *err)
 {
-	if (nft_jansson_parse_val(root, node_name, type, out) < 0)
+	if (nft_jansson_parse_val(root, node_name, type, out, err) < 0)
 		return -1;
 
 	if (*((uint32_t *)out) > NFT_REG_MAX){
@@ -142,38 +163,42 @@ int nft_jansson_parse_reg(json_t *root, const char *node_name, int type,
 }
 
 int nft_jansson_str2num(json_t *root, const char *node_name, int base,
-			void *out, enum nft_type type)
+			void *out, enum nft_type type, struct nft_parse_err *err)
 {
 	const char *str;
 
-	str = nft_jansson_parse_str(root, node_name);
+	str = nft_jansson_parse_str(root, node_name, err);
 	if (str == NULL)
 		return -1;
 
 	return nft_strtoi(str, base, out, type);
 }
 
-struct nft_rule_expr *nft_jansson_expr_parse(json_t *root)
+struct nft_rule_expr *nft_jansson_expr_parse(json_t *root,
+					     struct nft_parse_err *err)
 {
 	struct nft_rule_expr *e;
 	const char *type;
 	int ret;
 
-	type = nft_jansson_parse_str(root, "type");
+	type = nft_jansson_parse_str(root, "type", err);
 	if (type == NULL)
 		return NULL;
 
 	e = nft_rule_expr_alloc(type);
-	if (e == NULL)
-		return NULL;;
+	if (e == NULL) {
+		err->node_name = "type";
+		return NULL;
+	}
 
-	ret = e->ops->json_parse(e, root);
+	ret = e->ops->json_parse(e, root, err);
 
 	return ret < 0 ? NULL : e;
 }
 
 int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
-			       union nft_data_reg *data_reg)
+			       union nft_data_reg *data_reg,
+			       struct nft_parse_err *err)
 {
 	json_t *data;
 	const char *type;
@@ -181,24 +206,27 @@ int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
 
 	data = json_object_get(root, node_name);
 	if (data == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = node_name;
 		errno = EINVAL;
 		return -1;
 	}
 
 	data = json_object_get(data, "data_reg");
 	if (data == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = "data_reg";
 		errno = EINVAL;
 		return -1;
 	}
 
-	ret = nft_data_reg_json_parse(data_reg, data);
-
+	ret = nft_data_reg_json_parse(data_reg, data, err);
 	if (ret < 0) {
 		errno = EINVAL;
 		return -1;
 	}
 
-	type = nft_jansson_parse_str(data, "type");
+	type = nft_jansson_parse_str(data, "type", err);
 	if (type == NULL)
 		return -1;
 
@@ -209,29 +237,32 @@ int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
 	else if (strcmp(type, "chain") == 0)
 		return DATA_CHAIN;
 	else {
+		err->error = NFT_PARSE_EBADTYPE;
+		err->node_name = "type";
 		errno = EINVAL;
 		return -1;
 	}
 }
 
-int nft_set_elem_json_parse(struct nft_set_elem *e, json_t *root)
+int nft_set_elem_json_parse(struct nft_set_elem *e, json_t *root,
+			    struct nft_parse_err *err)
 {
 	uint32_t uval32;
 	int set_elem_data;
 
-	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_set_elem_attr_set_u32(e, NFT_SET_ELEM_ATTR_FLAGS, uval32);
 
-	if (nft_jansson_data_reg_parse(root, "key", &e->key) != DATA_VALUE)
+	if (nft_jansson_data_reg_parse(root, "key", &e->key, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
 
 	if (nft_jansson_node_exist(root, "data")) {
 		set_elem_data = nft_jansson_data_reg_parse(root, "data",
-							   &e->data);
+							   &e->data, err);
 		switch (set_elem_data) {
 		case DATA_VALUE:
 			e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
diff --git a/src/libnftables.map b/src/libnftables.map
index 7dc9aee..7279448 100644
--- a/src/libnftables.map
+++ b/src/libnftables.map
@@ -1,5 +1,10 @@
 LIBNFTABLES_1.0 {
 global:
+
+  nft_parse_err_alloc;
+  nft_parse_err_free;
+  nft_parse_perror;
+
   nft_table_alloc;
   nft_table_free;
   nft_table_attr_is_set;
diff --git a/src/mxml.c b/src/mxml.c
index 82156b7..bd09bb3 100644
--- a/src/mxml.c
+++ b/src/mxml.c
@@ -22,13 +22,18 @@
 #include <libnftables/set.h>
 
 #ifdef XML_PARSING
-mxml_node_t *nft_mxml_build_tree(const char *xml, const char *treename)
+mxml_node_t *nft_mxml_build_tree(const char *xml, const char *treename,
+				 struct nft_parse_err *err)
 {
 	mxml_node_t *tree;
 
 	tree = mxmlLoadString(NULL, xml, MXML_OPAQUE_CALLBACK);
-	if (tree == NULL)
+	if (tree == NULL) {
+		err->error = NFT_PARSE_EBADINPUT;
+		err->line = 0;
+		err->column = 0;
 		goto err;
+	}
 
 	if (strcmp(tree->value.opaque, treename) == 0)
 		return tree;
@@ -39,7 +44,8 @@ err:
 	return NULL;
 }
 
-struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node)
+struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node,
+					  struct nft_parse_err *err)
 {
 	mxml_node_t *tree;
 	struct nft_rule_expr *e;
@@ -48,8 +54,11 @@ struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node)
 	int ret;
 
 	expr_name = mxmlElementGetAttr(node, "type");
-	if (expr_name == NULL)
+	if (expr_name == NULL) {
+		err->node_name = "type";
+		err->error = NFT_PARSE_EMISSINGNODE;
 		goto err;
+	}
 
 	e = nft_rule_expr_alloc(expr_name);
 	if (e == NULL)
@@ -65,7 +74,7 @@ struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node)
 	if (tree == NULL)
 		goto err_expr;
 
-	ret = e->ops->xml_parse(e, tree);
+	ret = e->ops->xml_parse(e, tree, err);
 	mxmlDelete(tree);
 
 	return ret < 0 ? NULL : e;
@@ -77,20 +86,24 @@ err:
 	return NULL;
 }
 
-int nft_mxml_reg_parse(mxml_node_t *tree, const char *reg_name, uint32_t flags)
+int nft_mxml_reg_parse(mxml_node_t *tree, const char *reg_name, uint32_t flags,
+		       struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	uint64_t val;
 
 	node = mxmlFindElement(tree, tree, reg_name, NULL, NULL, flags);
 	if (node == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
 		errno = EINVAL;
 		goto err;
 	}
 
 	if (nft_strtoi(node->child->value.opaque, BASE_DEC, &val,
-		       NFT_TYPE_U64) != 0)
+		       NFT_TYPE_U64) != 0) {
+		err->error = NFT_PARSE_EBADTYPE;
 		goto err;
+	}
 
 	if (val > NFT_REG_MAX) {
 		errno = ERANGE;
@@ -98,73 +111,101 @@ int nft_mxml_reg_parse(mxml_node_t *tree, const char *reg_name, uint32_t flags)
 	}
 	return val;
 err:
+	err->node_name = reg_name;
 	return -1;
 }
 
 int nft_mxml_data_reg_parse(mxml_node_t *tree, const char *node_name,
-			    union nft_data_reg *data_reg, uint16_t flags)
+			    union nft_data_reg *data_reg, uint16_t flags,
+			    struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 
 	node = mxmlFindElement(tree, tree, node_name, NULL, NULL,
 			       MXML_DESCEND_FIRST);
 	if (node == NULL || node->child == NULL) {
-		if (!(flags & NFT_XML_OPT))
+		if (!(flags & NFT_XML_OPT)) {
+			err->error = NFT_PARSE_EMISSINGNODE;
+			err->node_name = node_name;
 			errno = EINVAL;
+		}
 
 		return DATA_NONE;
 	}
 
-	return nft_data_reg_xml_parse(data_reg, node);
+	return nft_data_reg_xml_parse(data_reg, node, err);
 }
 
 int
 nft_mxml_num_parse(mxml_node_t *tree, const char *node_name,
 		   uint32_t mxml_flags, int base, void *number,
-		   enum nft_type type, uint16_t flags)
+		   enum nft_type type, uint16_t flags,
+		   struct nft_parse_err *err)
 {
 	mxml_node_t *node = NULL;
+	int ret;
 
 	node = mxmlFindElement(tree, tree, node_name, NULL, NULL, mxml_flags);
 	if (node == NULL || node->child == NULL) {
-		if (!(flags & NFT_XML_OPT))
+		if (!(flags & NFT_XML_OPT)) {
 			errno = EINVAL;
-
+			err->node_name = node_name;
+			err->error = NFT_PARSE_EMISSINGNODE;
+		}
 		return -1;
 	}
-	return nft_strtoi(node->child->value.opaque, base, number, type);
+
+	ret = nft_strtoi(node->child->value.opaque, base, number, type);
+
+	if (ret != 0) {
+		err->error = NFT_PARSE_EBADTYPE;
+		err->node_name = node_name;
+	}
+	return ret;
 }
 
 const char *nft_mxml_str_parse(mxml_node_t *tree, const char *node_name,
-			       uint32_t mxml_flags, uint16_t flags)
+			       uint32_t mxml_flags, uint16_t flags,
+			       struct nft_parse_err *err)
 {
 	mxml_node_t *node;
+	const char *ret;
 
 	node = mxmlFindElement(tree, tree, node_name, NULL, NULL, mxml_flags);
 	if (node == NULL || node->child == NULL) {
-		if (!(flags & NFT_XML_OPT))
+		if (!(flags & NFT_XML_OPT)) {
 			errno = EINVAL;
-
+			err->node_name = node_name;
+			err->error = NFT_PARSE_EMISSINGNODE;
+		}
 		return NULL;
 	}
 
-	return node->child->value.opaque;
+	ret = node->child->value.opaque;
+	if (ret == NULL) {
+		err->node_name = node_name;
+		err->error = NFT_PARSE_EBADTYPE;
+	}
+	return ret;
 }
 
 int nft_mxml_family_parse(mxml_node_t *tree, const char *node_name,
-			  uint32_t mxml_flags, uint16_t flags)
+			  uint32_t mxml_flags, uint16_t flags,
+			  struct nft_parse_err *err)
 {
 	const char *family_str;
 	int family;
 
 	family_str = nft_mxml_str_parse(tree, node_name, mxml_flags,
-					flags);
+					flags, err);
 	if (family_str == NULL)
 		return -1;
 
 	family = nft_str2family(family_str);
-	if (family < 0)
+	if (family < 0) {
+		err->node_name = node_name;
 		errno = EAFNOSUPPORT;
+	}
 
 	return family;
 }
diff --git a/src/rule.c b/src/rule.c
index 280350a..2e35aba 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -442,7 +442,8 @@ int nft_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_rule *r)
 EXPORT_SYMBOL(nft_rule_nlmsg_parse);
 
 #ifdef JSON_PARSING
-int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
+int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree,
+			   struct nft_parse_err *err)
 {
 	json_t *root, *array;
 	struct nft_rule_expr *e;
@@ -451,28 +452,29 @@ int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
 	uint32_t uval32;
 	int i, family;
 
-	root = nft_jansson_get_node(tree, "rule");
+	root = nft_jansson_get_node(tree, "rule", err);
 	if (root == NULL)
 		return -1;
 
-	if (nft_jansson_parse_family(root, &family) != 0)
+	if (nft_jansson_parse_family(root, &family, err) != 0)
 		goto err;
 
 	nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, family);
 
-	str = nft_jansson_parse_str(root, "table");
+	str = nft_jansson_parse_str(root, "table", err);
 	if (str == NULL)
 		goto err;
 
 	nft_rule_attr_set_str(r, NFT_RULE_ATTR_TABLE, str);
 
-	str = nft_jansson_parse_str(root, "chain");
+	str = nft_jansson_parse_str(root, "chain", err);
 	if (str == NULL)
 		goto err;
 
 	nft_rule_attr_set_str(r, NFT_RULE_ATTR_CHAIN, str);
 
-	if (nft_jansson_parse_val(root, "handle", NFT_TYPE_U64, &uval64) < 0)
+	if (nft_jansson_parse_val(root, "handle", NFT_TYPE_U64, &uval64,
+				  err) < 0)
 		goto err;
 
 	nft_rule_attr_set_u64(r, NFT_RULE_ATTR_HANDLE, uval64);
@@ -480,13 +482,13 @@ int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
 	if (nft_jansson_node_exist(root, "compat_proto") ||
 	    nft_jansson_node_exist(root, "compat_flags")) {
 		if (nft_jansson_parse_val(root, "compat_proto", NFT_TYPE_U32,
-					  &uval32) < 0)
+					  &uval32, err) < 0)
 			goto err;
 
 		nft_rule_attr_set_u32(r, NFT_RULE_ATTR_COMPAT_PROTO, uval32);
 
 		if (nft_jansson_parse_val(root, "compat_flags", NFT_TYPE_U32,
-					  &uval32) < 0)
+					  &uval32, err) < 0)
 			goto err;
 
 		nft_rule_attr_set_u32(r, NFT_RULE_ATTR_COMPAT_FLAGS, uval32);
@@ -494,19 +496,22 @@ int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
 
 	if (nft_jansson_node_exist(root, "position")) {
 		if (nft_jansson_parse_val(root, "position", NFT_TYPE_U64,
-					  &uval64) < 0)
+					  &uval64, err) < 0)
 			goto err;
 
 		nft_rule_attr_set_u64(r, NFT_RULE_ATTR_POSITION, uval64);
 	}
 
 	array = json_object_get(root, "expr");
-	if (array == NULL)
+	if (array == NULL) {
+		err->error = NFT_PARSE_EMISSINGNODE;
+		err->node_name = "expr";
 		goto err;
+	}
 
 	for (i = 0; i < json_array_size(array); ++i) {
 
-		e = nft_jansson_expr_parse(json_array_get(array, i));
+		e = nft_jansson_expr_parse(json_array_get(array, i), err);
 		if (e == NULL)
 			goto err;
 
@@ -521,17 +526,18 @@ err:
 }
 #endif
 
-static int nft_rule_json_parse(struct nft_rule *r, const char *json)
+static int nft_rule_json_parse(struct nft_rule *r, const char *json,
+			       struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	json_t *tree;
 	json_error_t error;
 
-	tree = nft_jansson_create_root(json, &error);
+	tree = nft_jansson_create_root(json, &error, err);
 	if (tree == NULL)
 		return -1;
 
-	return nft_jansson_parse_rule(r, tree);
+	return nft_jansson_parse_rule(r, tree, err);
 #else
 	errno = EOPNOTSUPP;
 	return -1;
@@ -539,7 +545,8 @@ static int nft_rule_json_parse(struct nft_rule *r, const char *json)
 }
 
 #ifdef XML_PARSING
-int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
+int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r,
+			struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	struct nft_rule_expr *e;
@@ -547,7 +554,7 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 	int family;
 
 	family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
-				       NFT_XML_MAND);
+				       NFT_XML_MAND, err);
 	if (family < 0)
 		return -1;
 
@@ -555,7 +562,7 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 	r->flags |= (1 << NFT_RULE_ATTR_FAMILY);
 
 	table = nft_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
-				   NFT_XML_MAND);
+				   NFT_XML_MAND, err);
 	if (table == NULL)
 		return -1;
 
@@ -566,7 +573,7 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 	r->flags |= (1 << NFT_RULE_ATTR_TABLE);
 
 	chain = nft_mxml_str_parse(tree, "chain", MXML_DESCEND_FIRST,
-				   NFT_XML_MAND);
+				   NFT_XML_MAND, err);
 	if (chain == NULL)
 		return -1;
 
@@ -577,19 +584,19 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 	r->flags |= (1 << NFT_RULE_ATTR_CHAIN);
 
 	if (nft_mxml_num_parse(tree, "handle", MXML_DESCEND_FIRST, BASE_DEC,
-			       &r->handle, NFT_TYPE_U64, NFT_XML_MAND) != 0)
+			       &r->handle, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	r->flags |= (1 << NFT_RULE_ATTR_HANDLE);
 
 	if (nft_mxml_num_parse(tree, "compat_proto", MXML_DESCEND_FIRST,
 			       BASE_DEC, &r->compat.proto, NFT_TYPE_U32,
-			       NFT_XML_OPT) >= 0)
+			       NFT_XML_OPT, err) >= 0)
 		r->flags |= (1 << NFT_RULE_ATTR_COMPAT_PROTO);
 
 	if (nft_mxml_num_parse(tree, "compat_flags", MXML_DESCEND_FIRST,
 			       BASE_DEC, &r->compat.flags, NFT_TYPE_U32,
-			       NFT_XML_OPT) >= 0)
+			       NFT_XML_OPT, err) >= 0)
 		r->flags |= (1 << NFT_RULE_ATTR_COMPAT_FLAGS);
 
 	if (nft_rule_attr_is_set(r, NFT_RULE_ATTR_COMPAT_PROTO) !=
@@ -600,7 +607,7 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 
 	if (nft_mxml_num_parse(tree, "position", MXML_DESCEND_FIRST,
 			       BASE_DEC, &r->position, NFT_TYPE_U64,
-			       NFT_XML_OPT) >= 0)
+			       NFT_XML_OPT, err) >= 0)
 		r->flags |= (1 << NFT_RULE_ATTR_POSITION);
 
 	/* Iterating over <expr> */
@@ -609,7 +616,7 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 		node != NULL;
 		node = mxmlFindElement(node, tree, "expr", "type",
 				       NULL, MXML_DESCEND)) {
-		e = nft_mxml_expr_parse(node);
+		e = nft_mxml_expr_parse(node, err);
 		if (e == NULL)
 			return -1;
 
@@ -620,15 +627,16 @@ int nft_mxml_rule_parse(mxml_node_t *tree, struct nft_rule *r)
 }
 #endif
 
-static int nft_rule_xml_parse(struct nft_rule *r, const char *xml)
+static int nft_rule_xml_parse(struct nft_rule *r, const char *xml,
+			      struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	int ret;
-	mxml_node_t *tree = nft_mxml_build_tree(xml, "rule");
+	mxml_node_t *tree = nft_mxml_build_tree(xml, "rule", err);
 	if (tree == NULL)
 		return -1;
 
-	ret = nft_mxml_rule_parse(tree, r);
+	ret = nft_mxml_rule_parse(tree, r, err);
 	mxmlDelete(tree);
 	return ret;
 #else
@@ -638,22 +646,25 @@ static int nft_rule_xml_parse(struct nft_rule *r, const char *xml)
 }
 
 int nft_rule_parse(struct nft_rule *r, enum nft_parse_type type,
-		   const char *data)
+		   const char *data, struct nft_parse_err *err)
 {
 	int ret;
+	struct nft_parse_err perr;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_rule_xml_parse(r, data);
+		ret = nft_rule_xml_parse(r, data, &perr);
 		break;
 	case NFT_PARSE_JSON:
-		ret = nft_rule_json_parse(r, data);
+		ret = nft_rule_json_parse(r, data, &perr);
 		break;
 	default:
 		ret = -1;
 		errno = EOPNOTSUPP;
 		break;
 	}
+	if (err != NULL)
+		*err = perr;
 
 	return ret;
 }
diff --git a/src/ruleset.c b/src/ruleset.c
index f591382..a12efa9 100644
--- a/src/ruleset.c
+++ b/src/ruleset.c
@@ -132,7 +132,8 @@ const void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr)
 EXPORT_SYMBOL(nft_ruleset_attr_get);
 
 #ifdef JSON_PARSING
-static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array)
+static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array,
+					 struct nft_parse_err *err)
 {
 	int i, len;
 	json_t *node;
@@ -161,7 +162,7 @@ static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array)
 			goto err;
 		}
 
-		if (nft_jansson_parse_table(o, node) < 0) {
+		if (nft_jansson_parse_table(o, node, err) < 0) {
 			nft_table_free(o);
 			goto err;
 		}
@@ -180,7 +181,8 @@ err:
 	return -1;
 }
 
-static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array)
+static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array,
+					 struct nft_parse_err *err)
 {
 	int i, len;
 	json_t *node;
@@ -209,7 +211,7 @@ static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array)
 			goto err;
 		}
 
-		if (nft_jansson_parse_chain(o, node) < 0) {
+		if (nft_jansson_parse_chain(o, node, err) < 0) {
 			nft_chain_free(o);
 			goto err;
 		}
@@ -228,7 +230,8 @@ err:
 	return -1;
 }
 
-static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array)
+static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array,
+				       struct nft_parse_err *err)
 {
 	int i, len;
 	json_t *node;
@@ -257,7 +260,7 @@ static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array)
 			goto err;
 		}
 
-		if (nft_jansson_parse_set(s, node) < 0) {
+		if (nft_jansson_parse_set(s, node, err) < 0) {
 			nft_set_free(s);
 			goto err;
 		}
@@ -276,7 +279,8 @@ err:
 	return -1;
 }
 
-static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array)
+static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array,
+					struct nft_parse_err *err)
 {
 	int i, len;
 	json_t *node;
@@ -305,7 +309,7 @@ static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array)
 			goto err;
 		}
 
-		if (nft_jansson_parse_rule(o, node) < 0) {
+		if (nft_jansson_parse_rule(o, node, err) < 0) {
 			nft_rule_free(o);
 			goto err;
 		}
@@ -326,13 +330,14 @@ err:
 
 #endif
 
-static int nft_ruleset_json_parse(struct nft_ruleset *rs, const char *json)
+static int nft_ruleset_json_parse(struct nft_ruleset *rs, const char *json,
+				  struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	json_t *root, *array;
 	json_error_t error;
 
-	root = nft_jansson_create_root(json, &error);
+	root = nft_jansson_create_root(json, &error, err);
 	if (root == NULL)
 		return -1;
 
@@ -342,16 +347,16 @@ static int nft_ruleset_json_parse(struct nft_ruleset *rs, const char *json)
 		goto err;
 	}
 
-	if (nft_ruleset_json_parse_tables(rs, array) != 0)
+	if (nft_ruleset_json_parse_tables(rs, array, err) != 0)
 		goto err;
 
-	if (nft_ruleset_json_parse_chains(rs, array) != 0)
+	if (nft_ruleset_json_parse_chains(rs, array, err) != 0)
 		goto err;
 
-	if (nft_ruleset_json_parse_sets(rs, array) != 0)
+	if (nft_ruleset_json_parse_sets(rs, array, err) != 0)
 		goto err;
 
-	if (nft_ruleset_json_parse_rules(rs, array) != 0)
+	if (nft_ruleset_json_parse_rules(rs, array, err) != 0)
 		goto err;
 
 	nft_jansson_free_root(root);
@@ -367,7 +372,8 @@ err:
 
 #ifdef XML_PARSING
 static int
-nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree)
+nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree,
+			     struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	struct nft_table *t;
@@ -386,7 +392,7 @@ nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree)
 		if (t == NULL)
 			goto err_free;
 
-		if (nft_mxml_table_parse(node, t) != 0) {
+		if (nft_mxml_table_parse(node, t, err) != 0) {
 			nft_table_free(t);
 			goto err_free;
 		}
@@ -407,7 +413,8 @@ err_free:
 }
 
 static int
-nft_ruleset_xml_parse_chains(struct nft_ruleset *rs, mxml_node_t *tree)
+nft_ruleset_xml_parse_chains(struct nft_ruleset *rs, mxml_node_t *tree,
+			     struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	struct nft_chain *c;
@@ -426,7 +433,7 @@ nft_ruleset_xml_parse_chains(struct nft_ruleset *rs, mxml_node_t *tree)
 		if (c == NULL)
 			goto err_free;
 
-		if (nft_mxml_chain_parse(node, c) != 0) {
+		if (nft_mxml_chain_parse(node, c, err) != 0) {
 			nft_chain_free(c);
 			goto err_free;
 		}
@@ -447,7 +454,8 @@ err_free:
 }
 
 static int
-nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree)
+nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree,
+			   struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	struct nft_set *s;
@@ -466,7 +474,7 @@ nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree)
 		if (s == NULL)
 			goto err_free;
 
-		if (nft_mxml_set_parse(node, s) != 0) {
+		if (nft_mxml_set_parse(node, s, err) != 0) {
 			nft_set_free(s);
 			goto err_free;
 		}
@@ -486,7 +494,8 @@ err_free:
 }
 
 static int
-nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree)
+nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree,
+			    struct nft_parse_err *err)
 {
 	mxml_node_t *node;
 	struct nft_rule *r;
@@ -505,7 +514,7 @@ nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree)
 		if (r == NULL)
 			goto err_free;
 
-		if (nft_mxml_rule_parse(node, r) != 0) {
+		if (nft_mxml_rule_parse(node, r, err) != 0) {
 			nft_rule_free(r);
 			goto err_free;
 		}
@@ -525,25 +534,26 @@ err_free:
 }
 #endif
 
-static int nft_ruleset_xml_parse(struct nft_ruleset *rs, const char *xml)
+static int nft_ruleset_xml_parse(struct nft_ruleset *rs, const char *xml,
+				 struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	mxml_node_t *tree;
 
-	tree = nft_mxml_build_tree(xml, "nftables");
+	tree = nft_mxml_build_tree(xml, "nftables", err);
 	if (tree == NULL)
 		return -1;
 
-	if (nft_ruleset_xml_parse_tables(rs, tree) != 0)
+	if (nft_ruleset_xml_parse_tables(rs, tree, err) != 0)
 		goto err;
 
-	if (nft_ruleset_xml_parse_chains(rs, tree) != 0)
+	if (nft_ruleset_xml_parse_chains(rs, tree, err) != 0)
 		goto err;
 
-	if (nft_ruleset_xml_parse_sets(rs, tree) != 0)
+	if (nft_ruleset_xml_parse_sets(rs, tree, err) != 0)
 		goto err;
 
-	if (nft_ruleset_xml_parse_rules(rs, tree) != 0)
+	if (nft_ruleset_xml_parse_rules(rs, tree, err) != 0)
 		goto err;
 
 	mxmlDelete(tree);
@@ -558,16 +568,16 @@ err:
 }
 
 int nft_ruleset_parse(struct nft_ruleset *r, enum nft_parse_type type,
-		      const char *data)
+		      const char *data, struct nft_parse_err *err)
 {
 	int ret;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_ruleset_xml_parse(r, data);
+		ret = nft_ruleset_xml_parse(r, data, err);
 		break;
 	case NFT_PARSE_JSON:
-		ret = nft_ruleset_json_parse(r, data);
+		ret = nft_ruleset_json_parse(r, data, err);
 		break;
 	default:
 		ret = -1;
diff --git a/src/set.c b/src/set.c
index c5204cc..32c7fff 100644
--- a/src/set.c
+++ b/src/set.c
@@ -283,7 +283,8 @@ int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 EXPORT_SYMBOL(nft_set_nlmsg_parse);
 
 #ifdef JSON_PARSING
-int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
+int nft_jansson_parse_set(struct nft_set *s, json_t *tree,
+			  struct nft_parse_err *err)
 {
 	json_t *root, *array, *json_elem;
 	uint32_t uval32;
@@ -291,45 +292,47 @@ int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
 	const char *valstr;
 	struct nft_set_elem *elem;
 
-	root = nft_jansson_get_node(tree, "set");
+	root = nft_jansson_get_node(tree, "set", err);
 	if (root == NULL)
 		return -1;
 
-	valstr = nft_jansson_parse_str(root, "name");
+	valstr = nft_jansson_parse_str(root, "name", err);
 	if (valstr == NULL)
 		return -1;
 
 	nft_set_attr_set_str(s, NFT_SET_ATTR_NAME, valstr);
 
-	valstr = nft_jansson_parse_str(root, "table");
+	valstr = nft_jansson_parse_str(root, "table", err);
 	if (valstr == NULL)
 		return -1;
 
 	nft_set_attr_set_str(s, NFT_SET_ATTR_TABLE, valstr);
 
-	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &uval32, err) < 0)
 		return -1;
 
 	nft_set_attr_set_u32(s, NFT_SET_ATTR_FLAGS, uval32);
 
-	if (nft_jansson_parse_family(root, &family) < 0)
+	if (nft_jansson_parse_family(root, &family, err) < 0)
 		return -1;
 
 	nft_set_attr_set_u32(s, NFT_SET_ATTR_FAMILY, family);
 
-	if (nft_jansson_parse_val(root, "key_type", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "key_type", NFT_TYPE_U32, &uval32,
+				  err) < 0)
 		return -1;
 
 	nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_TYPE, uval32);
 
-	if (nft_jansson_parse_val(root, "key_len", NFT_TYPE_U32, &uval32) < 0)
+	if (nft_jansson_parse_val(root, "key_len", NFT_TYPE_U32, &uval32,
+				  err) < 0)
 		return -1;
 
 	nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_LEN, uval32);
 
 	if (nft_jansson_node_exist(root, "data_type")) {
 		if (nft_jansson_parse_val(root, "data_type", NFT_TYPE_U32,
-					  &uval32) < 0)
+					  &uval32, err) < 0)
 			goto err;
 
 		nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_TYPE, uval32);
@@ -337,7 +340,7 @@ int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
 
 	if (nft_jansson_node_exist(root, "data_len")) {
 		if (nft_jansson_parse_val(root, "data_len", NFT_TYPE_U32,
-					  &uval32) < 0)
+					  &uval32, err) < 0)
 			goto err;
 
 		nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_LEN, uval32);
@@ -354,7 +357,7 @@ int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
 			if (json_elem == NULL)
 				goto err;
 
-			if (nft_set_elem_json_parse(elem, json_elem) < 0)
+			if (nft_set_elem_json_parse(elem, json_elem, err) < 0)
 				goto err;
 
 			list_add_tail(&elem->head, &s->element_list);
@@ -371,17 +374,18 @@ err:
 }
 #endif
 
-static int nft_set_json_parse(struct nft_set *s, const char *json)
+static int nft_set_json_parse(struct nft_set *s, const char *json,
+			      struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	json_t *tree;
 	json_error_t error;
 
-	tree = nft_jansson_create_root(json, &error);
+	tree = nft_jansson_create_root(json, &error, err);
 	if (tree == NULL)
 		return -1;
 
-	return nft_jansson_parse_set(s, tree);
+	return nft_jansson_parse_set(s, tree, err);
 #else
 	errno = EOPNOTSUPP;
 	return -1;
@@ -389,7 +393,8 @@ static int nft_set_json_parse(struct nft_set *s, const char *json)
 }
 
 #ifdef XML_PARSING
-int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
+int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s,
+		       struct nft_parse_err *err)
 {
 	mxml_node_t *node = NULL;
 	struct nft_set_elem *elem;
@@ -397,7 +402,7 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 	int family;
 
 	name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
-				  NFT_XML_MAND);
+				  NFT_XML_MAND, err);
 	if (name == NULL)
 		return -1;
 
@@ -408,7 +413,7 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 	s->flags |= (1 << NFT_SET_ATTR_NAME);
 
 	table = nft_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
-				   NFT_XML_MAND);
+				   NFT_XML_MAND, err);
 	if (table == NULL)
 		return -1;
 
@@ -419,7 +424,7 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 	s->flags |= (1 << NFT_SET_ATTR_TABLE);
 
 	family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
-				       NFT_XML_MAND);
+				       NFT_XML_MAND, err);
 	if (family < 0)
 		return -1;
 
@@ -428,31 +433,31 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 	s->flags |= (1 << NFT_SET_ATTR_FAMILY);
 
 	if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
-			       &s->set_flags, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &s->set_flags, NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	s->flags |= (1 << NFT_SET_ATTR_FLAGS);
 
 	if (nft_mxml_num_parse(tree, "key_type", MXML_DESCEND_FIRST, BASE_DEC,
-			       &s->key_type, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &s->key_type, NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	s->flags |= (1 << NFT_SET_ATTR_KEY_TYPE);
 
 	if (nft_mxml_num_parse(tree, "key_len", MXML_DESCEND_FIRST, BASE_DEC,
-			       &s->key_len, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &s->key_len, NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	s->flags |= (1 << NFT_SET_ATTR_KEY_LEN);
 
 	if (nft_mxml_num_parse(tree, "data_type", MXML_DESCEND_FIRST, BASE_DEC,
-			       &s->data_type, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &s->data_type, NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	s->flags |= (1 << NFT_SET_ATTR_DATA_TYPE);
 
 	if (nft_mxml_num_parse(tree, "data_len", MXML_DESCEND_FIRST, BASE_DEC,
-			       &s->data_len, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       &s->data_len, NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	s->flags |= (1 << NFT_SET_ATTR_DATA_LEN);
@@ -467,7 +472,7 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 		if (elem == NULL)
 			return -1;
 
-		if (nft_mxml_set_elem_parse(node, elem) < 0)
+		if (nft_mxml_set_elem_parse(node, elem, err) < 0)
 			return -1;
 
 		list_add_tail(&elem->head, &s->element_list);
@@ -477,15 +482,16 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s)
 }
 #endif
 
-static int nft_set_xml_parse(struct nft_set *s, const char *xml)
+static int nft_set_xml_parse(struct nft_set *s, const char *xml,
+			     struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	int ret;
-	mxml_node_t *tree = nft_mxml_build_tree(xml, "set");
+	mxml_node_t *tree = nft_mxml_build_tree(xml, "set", err);
 	if (tree == NULL)
 		return -1;
 
-	ret = nft_mxml_set_parse(tree, s);
+	ret = nft_mxml_set_parse(tree, s, err);
 	mxmlDelete(tree);
 	return ret;
 #else
@@ -495,16 +501,17 @@ static int nft_set_xml_parse(struct nft_set *s, const char *xml)
 }
 
 int nft_set_parse(struct nft_set *s, enum nft_parse_type type,
-		  const char *data)
+		  const char *data, struct nft_parse_err *err)
 {
 	int ret;
+	struct nft_parse_err perr;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_set_xml_parse(s, data);
+		ret = nft_set_xml_parse(s, data, &perr);
 		break;
 	case NFT_PARSE_JSON:
-		ret = nft_set_json_parse(s, data);
+		ret = nft_set_json_parse(s, data, &perr);
 		break;
 	default:
 		ret = -1;
@@ -512,6 +519,9 @@ int nft_set_parse(struct nft_set *s, enum nft_parse_type type,
 		break;
 	}
 
+	if (err != NULL)
+		*err = perr;
+
 	return ret;
 }
 EXPORT_SYMBOL(nft_set_parse);
diff --git a/src/set_elem.c b/src/set_elem.c
index fce9c1d..7365aff 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -357,26 +357,27 @@ int nft_set_elems_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 EXPORT_SYMBOL(nft_set_elems_nlmsg_parse);
 
 #ifdef XML_PARSING
-int nft_mxml_set_elem_parse(mxml_node_t *tree, struct nft_set_elem *e)
+int nft_mxml_set_elem_parse(mxml_node_t *tree, struct nft_set_elem *e,
+			    struct nft_parse_err *err)
 {
 	int set_elem_data;
 
 	if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST,
 			       BASE_DEC, &e->set_elem_flags,
-			       NFT_TYPE_U32, NFT_XML_MAND) != 0)
+			       NFT_TYPE_U32, NFT_XML_MAND, err) != 0)
 		return -1;
 
 	e->flags |= (1 << NFT_SET_ELEM_ATTR_FLAGS);
 
 	if (nft_mxml_data_reg_parse(tree, "key", &e->key,
-				    NFT_XML_MAND) != DATA_VALUE)
+				    NFT_XML_MAND, err) != DATA_VALUE)
 		return -1;
 
 	e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
 
 	/* <set_elem_data> is not mandatory */
 	set_elem_data = nft_mxml_data_reg_parse(tree, "data",
-						&e->data, NFT_XML_OPT);
+						&e->data, NFT_XML_OPT, err);
 	switch (set_elem_data) {
 	case DATA_VALUE:
 		e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
@@ -393,17 +394,18 @@ int nft_mxml_set_elem_parse(mxml_node_t *tree, struct nft_set_elem *e)
 }
 #endif
 
-static int nft_set_elem_xml_parse(struct nft_set_elem *e, const char *xml)
+static int nft_set_elem_xml_parse(struct nft_set_elem *e, const char *xml,
+				  struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	mxml_node_t *tree;
 	int ret;
 
-	tree = nft_mxml_build_tree(xml, "set_elem");
+	tree = nft_mxml_build_tree(xml, "set_elem", err);
 	if (tree == NULL)
 		return -1;
 
-	ret = nft_mxml_set_elem_parse(tree, e);
+	ret = nft_mxml_set_elem_parse(tree, e, err);
 	mxmlDelete(tree);
 	return ret;
 #else
@@ -413,12 +415,13 @@ static int nft_set_elem_xml_parse(struct nft_set_elem *e, const char *xml)
 }
 
 int nft_set_elem_parse(struct nft_set_elem *e,
-		       enum nft_parse_type type, const char *data) {
+		       enum nft_parse_type type, const char *data,
+		       struct nft_parse_err *err) {
 	int ret;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_set_elem_xml_parse(e, data);
+		ret = nft_set_elem_xml_parse(e, data, err);
 		break;
 	default:
 		errno = EOPNOTSUPP;
diff --git a/src/table.c b/src/table.c
index 9e20768..9b5f5c9 100644
--- a/src/table.c
+++ b/src/table.c
@@ -211,13 +211,14 @@ int nft_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_table *t)
 EXPORT_SYMBOL(nft_table_nlmsg_parse);
 
 #ifdef XML_PARSING
-int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t)
+int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t,
+			 struct nft_parse_err *err)
 {
 	const char *name;
 	int family;
 
 	name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
-				  NFT_XML_MAND);
+				  NFT_XML_MAND, err);
 	if (name == NULL)
 		return -1;
 
@@ -228,7 +229,7 @@ int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t)
 	t->flags |= (1 << NFT_TABLE_ATTR_NAME);
 
 	family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
-				       NFT_XML_MAND);
+				       NFT_XML_MAND, err);
 	if (family < 0)
 		return -1;
 
@@ -237,7 +238,7 @@ int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t)
 
 	if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND, BASE_DEC,
 			       &t->table_flags, NFT_TYPE_U32,
-			       NFT_XML_MAND) != 0)
+			       NFT_XML_MAND, err) != 0)
 		return -1;
 
 	t->flags |= (1 << NFT_TABLE_ATTR_FLAGS);
@@ -246,15 +247,16 @@ int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t)
 }
 #endif
 
-static int nft_table_xml_parse(struct nft_table *t, const char *xml)
+static int nft_table_xml_parse(struct nft_table *t, const char *xml,
+			       struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	int ret;
-	mxml_node_t *tree = nft_mxml_build_tree(xml, "table");
+	mxml_node_t *tree = nft_mxml_build_tree(xml, "table", err);
 	if (tree == NULL)
 		return -1;
 
-	ret = nft_mxml_table_parse(tree, t);
+	ret = nft_mxml_table_parse(tree, t, err);
 	mxmlDelete(tree);
 	return ret;
 #else
@@ -264,29 +266,30 @@ static int nft_table_xml_parse(struct nft_table *t, const char *xml)
 }
 
 #ifdef JSON_PARSING
-int nft_jansson_parse_table(struct nft_table *t, json_t *tree)
+int nft_jansson_parse_table(struct nft_table *t, json_t *tree,
+			    struct nft_parse_err *err)
 {
 	json_t *root;
 	uint32_t flags;
 	const char *str;
 	int family;
 
-	root = nft_jansson_get_node(tree, "table");
+	root = nft_jansson_get_node(tree, "table", err);
 	if (root == NULL)
 		return -1;
 
-	str = nft_jansson_parse_str(root, "name");
+	str = nft_jansson_parse_str(root, "name", err);
 	if (str == NULL)
 		goto err;
 
 	nft_table_attr_set_str(t, NFT_TABLE_ATTR_NAME, str);
 
-	if (nft_jansson_parse_family(root, &family) != 0)
+	if (nft_jansson_parse_family(root, &family, err) != 0)
 		goto err;
 
 	nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FAMILY, family);
 
-	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &flags) < 0)
+	if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &flags, err) < 0)
 		goto err;
 
 	nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FLAGS, flags);
@@ -299,17 +302,18 @@ err:
 }
 #endif
 
-static int nft_table_json_parse(struct nft_table *t, const char *json)
+static int nft_table_json_parse(struct nft_table *t, const char *json,
+				struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	json_t *tree;
 	json_error_t error;
 
-	tree = nft_jansson_create_root(json, &error);
+	tree = nft_jansson_create_root(json, &error, err);
 	if (tree == NULL)
 		return -1;
 
-	return nft_jansson_parse_table(t, tree);
+	return nft_jansson_parse_table(t, tree, err);
 #else
 	errno = EOPNOTSUPP;
 	return -1;
@@ -317,16 +321,17 @@ static int nft_table_json_parse(struct nft_table *t, const char *json)
 }
 
 int nft_table_parse(struct nft_table *t, enum nft_parse_type type,
-		    const char *data)
+		    const char *data, struct nft_parse_err *err)
 {
 	int ret;
+	struct nft_parse_err perr;
 
 	switch (type) {
 	case NFT_PARSE_XML:
-		ret = nft_table_xml_parse(t, data);
+		ret = nft_table_xml_parse(t, data, &perr);
 		break;
 	case NFT_PARSE_JSON:
-		ret = nft_table_json_parse(t, data);
+		ret = nft_table_json_parse(t, data, &perr);
 		break;
 	default:
 		ret = -1;
@@ -334,6 +339,9 @@ int nft_table_parse(struct nft_table *t, enum nft_parse_type type,
 		break;
 	}
 
+	if (err != NULL)
+		*err = perr;
+
 	return ret;
 }
 EXPORT_SYMBOL(nft_table_parse);
diff --git a/tests/nft-parsing-test.c b/tests/nft-parsing-test.c
index 6a5ab4d..40ede9d 100644
--- a/tests/nft-parsing-test.c
+++ b/tests/nft-parsing-test.c
@@ -167,7 +167,7 @@ static int compare_test(uint32_t type, void *input, const char *filename)
 }
 #endif
 
-static int test_json(const char *filename)
+static int test_json(const char *filename, struct nft_parse_err *err)
 {
 #ifdef JSON_PARSING
 	int ret = -1;
@@ -182,7 +182,6 @@ static int test_json(const char *filename)
 
 	root = json_load_file(filename, 0, &error);
 	if (!root) {
-		printf("Error on the line %d : %s", error.line, error.text);
 		return -1;
 	}
 
@@ -191,7 +190,7 @@ static int test_json(const char *filename)
 	if (json_object_get(root, "table") != NULL) {
 		t = nft_table_alloc();
 		if (t != NULL) {
-			if (nft_table_parse(t, NFT_PARSE_JSON, json) == 0)
+			if (nft_table_parse(t, NFT_PARSE_JSON, json, err) == 0)
 				ret = compare_test(TEST_JSON_TABLE, t, filename);
 			else
 				goto failparsing;
@@ -201,7 +200,7 @@ static int test_json(const char *filename)
 	} else if (json_object_get(root, "chain") != NULL) {
 		c = nft_chain_alloc();
 		if (c != NULL) {
-			if (nft_chain_parse(c, NFT_PARSE_JSON, json) == 0)
+			if (nft_chain_parse(c, NFT_PARSE_JSON, json, err) == 0)
 				ret = compare_test(TEST_JSON_CHAIN, c, filename);
 			else
 				goto failparsing;
@@ -211,7 +210,7 @@ static int test_json(const char *filename)
 	} else if (json_object_get(root, "rule") != NULL) {
 		r = nft_rule_alloc();
 		if (r != NULL) {
-			if (nft_rule_parse(r, NFT_PARSE_JSON, json) == 0)
+			if (nft_rule_parse(r, NFT_PARSE_JSON, json, err) == 0)
 				ret = compare_test(TEST_JSON_RULE, r, filename);
 			else
 				goto failparsing;
@@ -221,7 +220,7 @@ static int test_json(const char *filename)
 	} else if (json_object_get(root, "set") != NULL) {
 		s = nft_set_alloc();
 		if (s != NULL) {
-			if (nft_set_parse(s, NFT_PARSE_JSON, json) == 0)
+			if (nft_set_parse(s, NFT_PARSE_JSON, json, err) == 0)
 				ret = compare_test(TEST_JSON_SET, s, filename);
 			else
 				goto failparsing;
@@ -231,7 +230,7 @@ static int test_json(const char *filename)
 	} else if (json_object_get(root, "nftables") != NULL) {
 		rs = nft_ruleset_alloc();
 		if (rs != NULL) {
-			if (nft_ruleset_parse(rs, NFT_PARSE_JSON, json) == 0)
+			if (nft_ruleset_parse(rs, NFT_PARSE_JSON, json, err) == 0)
 				ret = compare_test(TEST_JSON_RULESET, rs, filename);
 			else
 				goto failparsing;
@@ -256,7 +255,7 @@ failparsing:
 #endif
 }
 
-static int test_xml(const char *filename)
+static int test_xml(const char *filename, struct nft_parse_err *err)
 {
 #ifdef XML_PARSING
 	int ret = -1;
@@ -290,7 +289,7 @@ static int test_xml(const char *filename)
 	if (strcmp(tree->value.opaque, "table") == 0) {
 		t = nft_table_alloc();
 		if (t != NULL) {
-			if (nft_table_parse(t, NFT_PARSE_XML, xml) == 0)
+			if (nft_table_parse(t, NFT_PARSE_XML, xml, err) == 0)
 				ret = compare_test(TEST_XML_TABLE, t, filename);
 			else
 				goto failparsing;
@@ -300,7 +299,7 @@ static int test_xml(const char *filename)
 	} else if (strcmp(tree->value.opaque, "chain") == 0) {
 		c = nft_chain_alloc();
 		if (c != NULL) {
-			if (nft_chain_parse(c, NFT_PARSE_XML, xml) == 0)
+			if (nft_chain_parse(c, NFT_PARSE_XML, xml, err) == 0)
 				ret = compare_test(TEST_XML_CHAIN, c, filename);
 			else
 				goto failparsing;
@@ -310,7 +309,7 @@ static int test_xml(const char *filename)
 	} else if (strcmp(tree->value.opaque, "rule") == 0) {
 		r = nft_rule_alloc();
 		if (r != NULL) {
-			if (nft_rule_parse(r, NFT_PARSE_XML, xml) == 0)
+			if (nft_rule_parse(r, NFT_PARSE_XML, xml, err) == 0)
 				ret = compare_test(TEST_XML_RULE, r, filename);
 			else
 				goto failparsing;
@@ -320,7 +319,7 @@ static int test_xml(const char *filename)
 	} else if (strcmp(tree->value.opaque, "set") == 0) {
 		s = nft_set_alloc();
 		if (s != NULL) {
-			if (nft_set_parse(s, NFT_PARSE_XML, xml) == 0)
+			if (nft_set_parse(s, NFT_PARSE_XML, xml, err) == 0)
 				ret = compare_test(TEST_XML_SET, s, filename);
 			else
 				goto failparsing;
@@ -331,7 +330,7 @@ static int test_xml(const char *filename)
 		rs = nft_ruleset_alloc();
 		if (rs != NULL) {
 			if (nft_ruleset_parse(rs, NFT_PARSE_XML,
-					      xml) == 0)
+					      xml, err) == 0)
 				ret = compare_test(TEST_XML_RULESET, rs,
 						   filename);
 			else
@@ -361,6 +360,7 @@ int main(int argc, char *argv[])
 	struct dirent *dent;
 	char path[PATH_MAX];
 	int ret = 0, exit_code = 0;
+	struct nft_parse_err *err;
 
 	if (argc != 2) {
 		fprintf(stderr, "Usage: %s <directory>\n", argv[0]);
@@ -373,6 +373,12 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
+	err = nft_parse_err_alloc();
+	if (err == NULL) {
+		perror("error");
+		exit(EXIT_FAILURE);
+	}
+
 	while ((dent = readdir(d)) != NULL) {
 		int len = strlen(dent->d_name);
 
@@ -383,22 +389,25 @@ int main(int argc, char *argv[])
 		snprintf(path, sizeof(path), "%s/%s", argv[1], dent->d_name);
 
 		if (strcmp(&dent->d_name[len-4], ".xml") == 0) {
-			if ((ret = test_xml(path)) == 0) {
+			if ((ret = test_xml(path, err)) == 0) {
 				printf("parsing and validating %s: ", path);
 				printf("\033[32mOK\e[0m\n");
 			}
+
 			exit_code += ret;
 		}
 		if (strcmp(&dent->d_name[len-5], ".json") == 0) {
-			if ((ret = test_json(path)) == 0) {
+			if ((ret = test_json(path, err)) == 0) {
 				printf("parsing and validating %s: ", path);
 				printf("\033[32mOK\e[0m\n");
 			}
+
 			exit_code += ret;
 		}
 	}
 
 	closedir(d);
+	nft_parse_err_free(err);
 
 	if (exit_code != 0)
 		exit(EXIT_FAILURE);

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

             reply	other threads:[~2014-01-05 23:52 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-05 23:51 Alvaro Neira [this message]
2014-01-06 12:23 ` [libnftables PATCH v2] src: new error reporting approach for XML/JSON parsers Pablo Neira Ayuso
2014-01-06 22:46   ` Arturo Borrero Gonzalez
2014-01-06 23:35     ` Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140105235114.3752.26544.stgit@Ph0enix \
    --to=alvaroneay@gmail.com \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.