libyang CHANGE parsing/validation significantly refactored
diff --git a/src/common.c b/src/common.c
index b02a136..dc0e1a4 100644
--- a/src/common.c
+++ b/src/common.c
@@ -850,6 +850,38 @@
     return NULL;
 }
 
+int
+ly_new_node_validity(const struct lys_node *schema)
+{
+    int validity;
+
+    validity = LYD_VAL_OK;
+    switch (schema->nodetype) {
+    case LYS_LEAF:
+    case LYS_LEAFLIST:
+        if (((struct lys_node_leaf *)schema)->type.base == LY_TYPE_LEAFREF) {
+            validity |= LYD_VAL_LEAFREF;
+        }
+        validity |= LYD_VAL_MAND;
+        break;
+    case LYS_LIST:
+        validity |= LYD_VAL_UNIQUE;
+        /* fallthrough */
+    case LYS_CONTAINER:
+    case LYS_NOTIF:
+    case LYS_RPC:
+    case LYS_ACTION:
+    case LYS_ANYXML:
+    case LYS_ANYDATA:
+        validity |= LYD_VAL_MAND;
+        break;
+    default:
+        break;
+    }
+
+    return validity;
+}
+
 void *
 ly_realloc(void *ptr, size_t size)
 {
diff --git a/src/common.h b/src/common.h
index cdf2b36..6bc90bc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -362,6 +362,15 @@
 const char *transform_iffeat_schema2json(const struct lys_module *module, const char *expr);
 
 /**
+ * @brief Get a new node (non-validated) validity value.
+ *
+ * @param[in] schema Schema node of the new data node.
+ *
+ * @return Validity of the new node.
+ */
+int ly_new_node_validity(const struct lys_node *schema);
+
+/**
  * @brief Wrapper for realloc() call. The only difference is that if it fails to
  * allocate the requested memory, the original memory is freed as well.
  *
diff --git a/src/log.c b/src/log.c
index abb10b5..f07a58e 100644
--- a/src/log.c
+++ b/src/log.c
@@ -185,7 +185,7 @@
 /* LYE_KEY_DUP */      "Key identifier \"%s\" is not unique.",
 /* LYE_INREGEX */      "Regular expression \"%s\" is not valid (\"%s\": %s).",
 /* LYE_INRESOLV */     "Failed to resolve %s \"%s\".",
-/* LYE_INSTATUS */     "A \"%s\" definition %s references \"%s\" definition %s.",
+/* LYE_INSTATUS */     "A %s definition \"%s\" references %s definition \"%s\".",
 /* LYE_CIRC_LEAFREFS */"A circular chain of leafrefs detected.",
 /* LYE_CIRC_FEATURES */"A circular chain features detected in \"%s\" feature.",
 /* LYE_CIRC_IMPORTS */ "A circular dependency (import) for module \"%s\".",
diff --git a/src/parser.c b/src/parser.c
index 8e7e0a0..55c5528 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1130,13 +1130,12 @@
 
 /*
  * xml  - optional for converting instance-identifier and identityref into JSON format
- * tree - optional for resolving instance-identifiers and leafrefs
  * leaf - mandatory to know the context (necessary e.g. for prefixes in idenitytref values)
- * store - flag for storing parsed data
+ * store - flag for union resolution - we do not want to store the result, we are just learning the type
  */
 struct lys_type *
-lyp_parse_value(struct lys_type *type, const char **value_, struct lyxml_elem *xml, struct lyd_node *tree,
-                        struct lyd_node_leaf_list *leaf, int store, int resolvable, int dflt)
+lyp_parse_value(struct lys_type *type, const char **value_, struct lyxml_elem *xml, struct lyd_node_leaf_list *leaf,
+                int store, int dflt)
 {
     struct lys_type *ret = NULL, *t;
     int c, i, j, len, found = 0, hidden;
@@ -1148,11 +1147,7 @@
 
     assert(leaf);
 
-    if (store) {
-        leaf->value_type = type->base;
-    }
-
-    switch(type->base) {
+    switch (type->base) {
     case LY_TYPE_BINARY:
         /* get number of octets for length validation */
         unum = 0;
@@ -1190,6 +1185,7 @@
         if (store) {
             /* store the result */
             leaf->value.binary = value;
+            leaf->value_type = LY_TYPE_BINARY;
         }
         break;
 
@@ -1213,6 +1209,7 @@
             if (store) {
                 /* store empty array */
                 leaf->value.bit = bits;
+                leaf->value_type = LY_TYPE_BITS;
             }
             break;
         }
@@ -1276,6 +1273,7 @@
         if (store) {
             /* store the result */
             leaf->value.bit = bits;
+            leaf->value_type = LY_TYPE_BITS;
         } else {
             free(bits);
         }
@@ -1291,6 +1289,10 @@
             goto cleanup;
         }
         /* else stays 0 */
+
+        if (store) {
+            leaf->value_type = LY_TYPE_BOOL;
+        }
         break;
 
     case LY_TYPE_DEC64:
@@ -1314,6 +1316,7 @@
         if (store) {
             /* store the result */
             leaf->value.dec64 = num;
+            leaf->value_type = LY_TYPE_DEC64;
         }
         break;
 
@@ -1322,6 +1325,10 @@
             LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
             goto cleanup;
         }
+
+        if (store) {
+            leaf->value_type = LY_TYPE_EMPTY;
+        }
         break;
 
     case LY_TYPE_ENUM:
@@ -1345,6 +1352,7 @@
                 /* ... and store pointer to the definition */
                 if (store) {
                     leaf->value.enm = &type->info.enums.enm[i];
+                    leaf->value_type = LY_TYPE_ENUM;
                 }
                 found = 1;
                 break;
@@ -1413,6 +1421,7 @@
         } else if (store) {
             /* store the result */
             leaf->value.ident = ident;
+            leaf->value_type = LY_TYPE_IDENT;
         }
 
         make_canonical(type->parent->module->ctx, LY_TYPE_IDENT, &value,
@@ -1460,13 +1469,11 @@
                 ly_vlog_hide(0);
             }
         }
-        if (resolvable && tree && !resolve_instid(tree, value) && (ly_errno || type->info.inst.req)) {
-            LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
-            goto cleanup;
-        } else if (!resolvable && store) {
-            /* make the note that the data node is not resolvable instance-identifier,
-             * because based on the data type the target is not necessary the part of the tree */
-            leaf->value_type |= LY_TYPE_INST_UNRES;
+
+        if (store) {
+            /* note that the data node is an unresolved instance-identifier */
+            leaf->value.instance = NULL;
+            leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
         }
 
         if (value != *value_) {
@@ -1489,30 +1496,16 @@
 
         /* it is called not only to get the final type, but mainly to update value to canonical or JSON form
          * if needed */
-        t = lyp_parse_value(&type->info.lref.target->type, value_, xml, tree, leaf, 0, resolvable, dflt);
+        t = lyp_parse_value(&type->info.lref.target->type, value_, xml, leaf, 0, dflt);
         value = *value_; /* refresh possibly changed value */
         if (!t) {
             LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, value, leaf->schema->name);
             goto cleanup;
         }
 
-        if (!resolvable && store) {
-            /* the leafref will not be resolved because of the data tree type which make possible that the
-             * target is not present in the data tree. Therefore, instead of leafref type, we store into the
-             * leaf the target type of the leafref with the note that it is unresolved leafref */
+        if (store) {
+            /* make the note that the data node is an unresolved leafref (value union was already filled) */
             leaf->value_type = t->base | LY_TYPE_LEAFREF_UNRES;
-        } else if (store) {
-            /* if the leaf is resolvable, its type is kept as LY_TYPE_LEAFREF */
-            leaf->value_type = LY_TYPE_LEAFREF;
-
-            /* erase possible error from ly_parse_value() calling */
-            ly_err_clean(1);
-
-            /* if we have the complete tree, resolve the leafref */
-            if (tree && resolve_leafref(leaf, type) && type->info.lref.req != -1) {
-                /* failure */
-                goto cleanup;
-            }
         }
 
         type = t;
@@ -1530,6 +1523,7 @@
         if (store) {
             /* store the result */
             leaf->value.string = value;
+            leaf->value_type = LY_TYPE_STRING;
         }
         break;
 
@@ -1544,6 +1538,7 @@
         if (store) {
             /* store the result */
             leaf->value.int8 = (int8_t)num;
+            leaf->value_type = LY_TYPE_INT8;
         }
         break;
 
@@ -1558,6 +1553,7 @@
         if (store) {
             /* store the result */
             leaf->value.int16 = (int16_t)num;
+            leaf->value_type = LY_TYPE_INT16;
         }
         break;
 
@@ -1572,6 +1568,7 @@
         if (store) {
             /* store the result */
             leaf->value.int32 = (int32_t)num;
+            leaf->value_type = LY_TYPE_INT32;
         }
         break;
 
@@ -1587,6 +1584,7 @@
         if (store) {
             /* store the result */
             leaf->value.int64 = num;
+            leaf->value_type = LY_TYPE_INT64;
         }
         break;
 
@@ -1601,6 +1599,7 @@
         if (store) {
             /* store the result */
             leaf->value.uint8 = (uint8_t)unum;
+            leaf->value_type = LY_TYPE_UINT8;
         }
         break;
 
@@ -1615,6 +1614,7 @@
         if (store) {
             /* store the result */
             leaf->value.uint16 = (uint16_t)unum;
+            leaf->value_type = LY_TYPE_UINT16;
         }
         break;
 
@@ -1629,6 +1629,7 @@
         if (store) {
             /* store the result */
             leaf->value.uint32 = (uint32_t)unum;
+            leaf->value_type = LY_TYPE_UINT32;
         }
         break;
 
@@ -1643,10 +1644,31 @@
         if (store) {
             /* store the result */
             leaf->value.uint64 = unum;
+            leaf->value_type = LY_TYPE_UINT64;
         }
         break;
 
     case LY_TYPE_UNION:
+        if (store) {
+            /* unresolved union type */
+            leaf->value_type = LY_TYPE_UNION;
+        }
+
+        if (type->info.uni.has_ptr_type) {
+            /* we are not resolving anything here, only parsing, and in this case we cannot decide
+             * the type without resolving it -> we return the union type (resolve it with resolve_union()) */
+            if (xml) {
+                /* in case it should resolve into a instance-identifier, we can only do the JSON conversion here */
+                leaf->value.string = transform_xml2json(type->parent->module->ctx, value, xml, 0);
+                if (!leaf->value.string) {
+                    /* invalid instance-identifier format */
+                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, *value_, leaf->schema->name);
+                    goto cleanup;
+                }
+            }
+            break;
+        }
+
         t = NULL;
         found = 0;
 
@@ -1656,7 +1678,7 @@
 
         while ((t = lyp_get_next_union_type(type, t, &found))) {
             found = 0;
-            ret = lyp_parse_value(t, value_, xml, tree, leaf, store, resolvable, dflt);
+            ret = lyp_parse_value(t, value_, xml, leaf, store, dflt);
             if (ret) {
                 /* we have the result */
                 type = ret;
@@ -1698,7 +1720,6 @@
     ret = type;
 
 cleanup:
-
     return ret;
 }
 
diff --git a/src/parser.h b/src/parser.h
index 325f50f..b254f3e 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -63,8 +63,7 @@
 struct lys_type *lyp_get_next_union_type(struct lys_type *type, struct lys_type *prev_type, int *found);
 
 struct lys_type *lyp_parse_value(struct lys_type *type, const char **value_, struct lyxml_elem *xml,
-                                         struct lyd_node *tree, struct lyd_node_leaf_list *leaf,
-                                         int store, int resolvable, int dflt);
+                                struct lyd_node_leaf_list *leaf, int store, int dflt);
 
 int lyp_check_length_range(const char *expr, struct lys_type *type);
 
diff --git a/src/parser_json.c b/src/parser_json.c
index b73103d..63c4a37 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -442,24 +442,17 @@
 }
 
 static unsigned int
-json_get_value(struct lyd_node_leaf_list *leaf, struct lyd_node *first_sibling, const char *data, int options)
+json_get_value(struct lyd_node_leaf_list *leaf, struct lyd_node *first_sibling, const char *data)
 {
     struct lyd_node_leaf_list *new;
     struct lys_type *stype;
     struct ly_ctx *ctx;
     unsigned int len = 0, r;
-    int resolvable;
     char *str;
 
     assert(leaf && data);
     ctx = leaf->schema->module->ctx;
 
-    if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
-        resolvable = 0;
-    } else {
-        resolvable = 1;
-    }
-
     stype = &((struct lys_node_leaf *)leaf->schema)->type;
 
     if (leaf->schema->nodetype == LYS_LEAFLIST) {
@@ -530,8 +523,7 @@
 
     /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
      * canonical form of the value */
-    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, NULL, leaf, 1,
-                         resolvable, 0)) {
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, leaf, 1, 0)) {
         ly_errno = LY_EVALID;
         return 0;
     }
@@ -1015,7 +1007,7 @@
             first_sibling = result;
         }
     }
-    result->validity = LYD_VAL_NOT;
+    result->validity = ly_new_node_validity(result->schema);
     if (resolve_applies_when(schema, 0, NULL)) {
         result->when_status = LYD_WHEN;
     }
@@ -1023,7 +1015,7 @@
     /* type specific processing */
     if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
         /* type detection and assigning the value */
-        r = json_get_value((struct lyd_node_leaf_list *)result, first_sibling, &data[len], options);
+        r = json_get_value((struct lyd_node_leaf_list *)result, first_sibling, &data[len]);
         if (!r) {
             goto error;
         }
@@ -1161,8 +1153,6 @@
                         goto error;
                     }
                 }
-                /* validation successful */
-                list->validity = LYD_VAL_OK;
 
                 /* another instance of the list */
                 new = calloc(1, sizeof *new);
@@ -1191,14 +1181,13 @@
     }
 
     /* various validation checks */
-    if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(result, options, unres)) {
+    if (lyv_data_context(result, options, unres)) {
         goto error;
     }
 
     ly_err_clean(1);
-    if (!(options & LYD_OPT_TRUSTED) &&
-            (lyv_data_content(result, options, unres) ||
-             lyv_multicases(result, NULL, prev ? &first_sibling : NULL, 0, NULL))) {
+    if (lyv_data_content(result, options, unres) ||
+             lyv_multicases(result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
         if (ly_errno) {
             goto error;
         }
@@ -1206,10 +1195,8 @@
 
     /* validation successful */
     if (result->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
-        /* postpone checking when there will be all list/leaflist instances */
-        result->validity = LYD_VAL_UNIQUE;
-    } else {
-        result->validity = LYD_VAL_OK;
+        /* postpone checking of unique when there will be all list/leaflist instances */
+        result->validity |= LYD_VAL_UNIQUE;
     }
 
     if (!(*parent)) {
diff --git a/src/parser_xml.c b/src/parser_xml.c
index ad1da1a..77d7f86 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -75,19 +75,12 @@
 
 /* logs directly */
 static int
-xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, int editbits)
+xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int editbits)
 {
     struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
-    int resolvable;
 
     assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml);
 
-    if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
-        resolvable = 0;
-    } else {
-        resolvable = 1;
-    }
-
     leaf->value_str = lydict_insert(node->schema->module->ctx, xml->content, 0);
 
     if ((editbits & 0x10) && (node->schema->nodetype & LYS_LEAF) && (!leaf->value_str || !leaf->value_str[0])) {
@@ -99,8 +92,7 @@
 
     /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
      * canonical form of the value */
-    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, NULL, leaf, 1,
-                         resolvable, 0)) {
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, leaf, 1, 0)) {
         return EXIT_FAILURE;
     }
 
@@ -280,7 +272,7 @@
             first_sibling = *result;
         }
     }
-    (*result)->validity = LYD_VAL_NOT;
+    (*result)->validity = ly_new_node_validity((*result)->schema);
     if (resolve_applies_when(schema, 0, NULL)) {
         (*result)->when_status = LYD_WHEN;
     }
@@ -382,7 +374,7 @@
     /* type specific processing */
     if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
         /* type detection and assigning the value */
-        if (xml_get_value(*result, xml, options, editbits)) {
+        if (xml_get_value(*result, xml, editbits)) {
             goto error;
         }
     } else if (schema->nodetype & LYS_ANYDATA) {
@@ -420,7 +412,7 @@
     }
 
     /* first part of validation checks */
-    if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, unres)) {
+    if (lyv_data_context(*result, options, unres)) {
         goto error;
     }
 
@@ -523,9 +515,8 @@
 
     /* rest of validation checks */
     ly_err_clean(1);
-    if (!(options & LYD_OPT_TRUSTED) &&
-            (lyv_data_content(*result, options, unres) ||
-             lyv_multicases(*result, NULL, prev ? &first_sibling : NULL, 0, NULL))) {
+    if (lyv_data_content(*result, options, unres) ||
+             lyv_multicases(*result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
         if (ly_errno) {
             goto error;
         } else {
@@ -536,9 +527,7 @@
     /* validation successful */
     if ((*result)->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
         /* postpone checking when there will be all list/leaflist instances */
-        (*result)->validity = LYD_VAL_UNIQUE;
-    } else {
-        (*result)->validity = LYD_VAL_OK;
+        (*result)->validity |= LYD_VAL_UNIQUE;
     }
 
     return ret;
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 9081bf0..595342a 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1245,6 +1245,10 @@
                     goto error;
                 }
             }
+            if ((dertype->base == LY_TYPE_INST) || (dertype->base == LY_TYPE_LEAFREF)
+                    || ((dertype->base == LY_TYPE_UNION) && dertype->info.uni.has_ptr_type)) {
+                typ->type->info.uni.has_ptr_type = 1;
+            }
         }
         break;
 
@@ -1954,7 +1958,7 @@
     }
 
     /* flag will be checked again, clear it for now */
-    dev->target->flags &= ~LYS_VALID_DEP;
+    dev->target->flags &= ~LYS_XPATH_DEP;
 
     if (dev->deviate->mod == LY_DEVIATE_ADD) {
         /* reallocate the must array of the target */
diff --git a/src/parser_yin.c b/src/parser_yin.c
index b767496..f3baba7 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -1184,6 +1184,11 @@
             goto error;
         }
 
+        /* inherit instid presence information */
+        if ((type->der->type.base == LY_TYPE_UNION) && type->der->type.info.uni.has_ptr_type) {
+            type->info.uni.has_ptr_type = 1;
+        }
+
         /* allocate array for union's types ... */
         type->info.uni.types = calloc(i, sizeof *type->info.uni.types);
         if (!type->info.uni.types) {
@@ -1207,6 +1212,11 @@
                         rc = -1;
                     }
                 }
+
+                if ((type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_INST)
+                        || (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_LEAFREF)) {
+                    type->info.uni.has_ptr_type = 1;
+                }
             }
             if (rc) {
                 /* even if we got EXIT_FAILURE, throw it all away, too much trouble doing something else */
@@ -1216,6 +1226,7 @@
                 free(type->info.uni.types);
                 type->info.uni.types = NULL;
                 type->info.uni.count = 0;
+                type->info.uni.has_ptr_type = 0;
                 type->der = NULL;
                 type->base = LY_TYPE_DER;
 
@@ -2044,7 +2055,7 @@
                 goto error;
             }
 
-            dev_target->flags &= ~LYS_VALID_DEP;
+            dev_target->flags &= ~LYS_XPATH_DEP;
 
             if (d->mod == LY_DEVIATE_RPL) {
                 /* replace must is forbidden */
diff --git a/src/printer_json.c b/src/printer_json.c
index 2d19836..e513c33 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -86,11 +86,10 @@
 static void
 json_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int onlyvalue, int toplevel, int options)
 {
-    struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
+    struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
     const char *schema = NULL, *p, *mod_name;
     const struct lys_module *wdmod = NULL;
     LY_DATA_TYPE datatype;
-    const struct lys_type *type;
     size_t len;
 
     if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
@@ -148,14 +147,18 @@
         break;
 
     case LY_TYPE_LEAFREF:
-        type = lyd_leaf_type(leaf, 1);
-        if (!type) {
+        iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
+        while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
+            iter = (struct lyd_node_leaf_list *)iter->value.leafref;
+        }
+        if (!iter) {
             /* error */
             ly_print(out, "\"(!error!)\"");
-            break;
+        } else {
+            datatype = iter->value_type & LY_DATA_TYPE_MASK;
+            goto contentprint;
         }
-        datatype = type->base;
-        goto contentprint;
+        break;
 
     case LY_TYPE_EMPTY:
         ly_print(out, "[null]");
@@ -441,6 +444,10 @@
             continue;
         }
 
+        if (node->validity) {
+            LOGWRN("Printing invalidated node \"%s\" (flags %d)!", node->schema->name, node->validity);
+        }
+
         switch (node->schema->nodetype) {
         case LYS_RPC:
         case LYS_ACTION:
diff --git a/src/printer_xml.c b/src/printer_xml.c
index 4296a97..ac4e56e 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -179,12 +179,11 @@
 static void
 xml_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
 {
-    const struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
+    const struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
     const char *ns, *mod_name;
     const char **prefs, **nss;
     const char *xml_expr;
     uint32_t ns_count, i;
-    struct lys_type *type;
     LY_DATA_TYPE datatype;
     char *p;
     size_t len;
@@ -202,7 +201,6 @@
     }
 
     xml_print_attrs(out, node, options);
-    type = &((struct lys_node_leaf *)leaf->schema)->type;
     datatype = leaf->value_type & LY_DATA_TYPE_MASK;
 printvalue:
     switch (datatype) {
@@ -274,13 +272,15 @@
         break;
 
     case LY_TYPE_LEAFREF:
-        type = lyp_parse_value(type, (const char **)&leaf->value_str, NULL, (struct lyd_node *)leaf,
-                               (struct lyd_node_leaf_list *)leaf, 0, 1, 0);
-        if (!type) {
+        iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
+        while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
+            iter = (struct lyd_node_leaf_list *)iter->value.leafref;
+        }
+        if (!iter) {
             /* error */
             ly_print(out, "\"(!error!)\"");
         } else {
-            datatype = type->base;
+            datatype = iter->value_type & LY_DATA_TYPE_MASK;
             goto printvalue;
         }
         break;
@@ -445,6 +445,10 @@
         return;
     }
 
+    if (node->validity) {
+        LOGWRN("Printing invalidated node \"%s\" (flags %d)!", node->schema->name, node->validity);
+    }
+
     switch (node->schema->nodetype) {
     case LYS_NOTIF:
     case LYS_RPC:
diff --git a/src/resolve.c b/src/resolve.c
index 509b6c7..084ee1c 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -30,8 +30,6 @@
 #include "dict_private.h"
 #include "tree_internal.h"
 
-static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
-
 int
 parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
 {
@@ -2183,7 +2181,6 @@
     int nam_len, val_len, has_predicate = 1, r;
     uint16_t i;
     struct lyd_node_leaf_list *key;
-    const struct lys_type *type;
 
     assert(node);
     assert(node->schema->nodetype == LYS_LIST);
@@ -2216,8 +2213,7 @@
         }
 
         /* make value canonical */
-        type = lyd_leaf_type(key, 1);
-        if ((type->base == LY_TYPE_IDENT)
+        if ((key->value_type & LY_TYPE_IDENT)
                 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
                 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
             key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
@@ -2260,7 +2256,6 @@
     int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
     struct lyd_node *sibling, *last_match = NULL;
     struct lyd_node_leaf_list *llist;
-    const struct lys_type *type;
     const struct lys_module *prefix_mod, *prev_mod;
     struct ly_ctx *ctx;
 
@@ -2372,8 +2367,7 @@
                     }
 
                     /* make value canonical */
-                    type = lyd_leaf_type(llist, 1);
-                    if ((type->base == LY_TYPE_IDENT)
+                    if ((llist->value_type & LY_TYPE_IDENT)
                             && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
                             && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
                         data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
@@ -3119,7 +3113,7 @@
             }
         }
     } else {
-        if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, NULL, &node, 1, 1, 1)) {
+        if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, 1, 1)) {
             /* possible forward reference */
             ret = 1;
             if (base_tpdf) {
@@ -3781,7 +3775,7 @@
 
             if (first_iter) {
                 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
-                    parent->flags |= LYS_VALID_DEP;
+                    parent->flags |= LYS_LEAFREF_DEP;
                 }
                 first_iter = 0;
             }
@@ -3963,7 +3957,7 @@
             /* set external dependency flag, we can decide based on the first found node */
             if (!parent_tpdf && op_node && parent_times &&
                     resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
-                parent->flags |= LYS_VALID_DEP;
+                parent->flags |= LYS_LEAFREF_DEP;
             }
             first_iter = 0;
         }
@@ -4141,93 +4135,6 @@
     return parsed;
 }
 
-/**
- * @brief Resolve instance-identifier in JSON data format. Logs directly.
- *
- * @param[in] data Data node where the path is used
- * @param[in] path Instance-identifier node value.
- *
- * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
- */
-struct lyd_node *
-resolve_instid(struct lyd_node *data, const char *path)
-{
-    int i = 0, j;
-    struct lyd_node *result = NULL;
-    const struct lys_module *mod;
-    struct ly_ctx *ctx = data->schema->module->ctx;
-    const char *model, *name;
-    char *str;
-    int mod_len, name_len, has_predicate;
-    struct unres_data node_match;
-
-    memset(&node_match, 0, sizeof node_match);
-
-    /* we need root to resolve absolute path */
-    for (; data->parent; data = data->parent);
-    /* we're still parsing it and the pointer is not correct yet */
-    if (data->prev) {
-        for (; data->prev->next; data = data->prev);
-    }
-
-    /* search for the instance node */
-    while (path[i]) {
-        j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
-        if (j <= 0) {
-            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
-            goto error;
-        }
-        i += j;
-
-        str = strndup(model, mod_len);
-        if (!str) {
-            LOGMEM;
-            goto error;
-        }
-        mod = ly_ctx_get_module(ctx, str, NULL);
-        free(str);
-
-        if (resolve_data(mod, name, name_len, data, &node_match)) {
-            /* no instance exists */
-            return NULL;
-        }
-
-        if (has_predicate) {
-            /* we have predicate, so the current results must be list or leaf-list */
-            j = resolve_predicate(&path[i], &node_match);
-            if (j < 1) {
-                LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
-                goto error;
-            }
-            i += j;
-
-            if (!node_match.count) {
-                /* no instance exists */
-                return NULL;
-            }
-        }
-    }
-
-    if (!node_match.count) {
-        /* no instance exists */
-        return NULL;
-    } else if (node_match.count > 1) {
-        /* instance identifier must resolve to a single node */
-        LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
-        goto error;
-    } else {
-        /* we have required result, remember it and cleanup */
-        result = node_match.node[0];
-        free(node_match.node);
-        return result;
-    }
-
-error:
-    /* cleanup */
-    free(node_match.node);
-    return NULL;
-}
-
 int
 lys_check_xpath(struct lys_node *node, int check_place)
 {
@@ -4282,7 +4189,7 @@
                 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
                 if (!elem) {
                     /* not in node's RPC or notification subtree, set the flag */
-                    node->flags |= LYS_VALID_DEP;
+                    node->flags |= LYS_XPATH_DEP;
                     break;
                 }
             }
@@ -5385,7 +5292,7 @@
  * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
  */
 static int
-resolve_must(struct lyd_node *node, int inout_parent)
+resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
 {
     uint8_t i, must_size;
     struct lys_node *schema;
@@ -5446,21 +5353,25 @@
     }
 
     for (i = 0; i < must_size; ++i) {
-        if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
+        if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
             return -1;
         }
 
-        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
+        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
 
         if (!set.val.bool) {
-            LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
-            if (must[i].emsg) {
-                LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
+            if (ignore_fail) {
+                LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
+            } else {
+                LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
+                if (must[i].emsg) {
+                    LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
+                }
+                if (must[i].eapptag) {
+                    strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
+                }
+                return 1;
             }
-            if (must[i].eapptag) {
-                strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
-            }
-            return 1;
         }
     }
 
@@ -5563,7 +5474,7 @@
 
 /**
  * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
- * The context nodes is adjusted if needed.
+ * The context node is adjusted if needed.
  *
  * @param[in] snode Schema node, whose children instances need to be unlinked.
  * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
@@ -5637,7 +5548,7 @@
                 /* temporarily unlink the node */
                 lyd_unlink(elem);
                 if (*unlinked_nodes) {
-                    if (lyd_insert_after(*unlinked_nodes, elem)) {
+                    if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
                         LOGINT;
                         return -1;
                     }
@@ -5800,7 +5711,7 @@
  *   1, ly_vecode = LYVE_INWHEN - nodes needed to resolve are conditional and not yet resolved (under another "when")
  */
 int
-resolve_when(struct lyd_node *node, int *result)
+resolve_when(struct lyd_node *node, int *result, int ignore_fail)
 {
     struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
     struct lys_node *sparent;
@@ -5814,7 +5725,8 @@
     if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
         /* make the node dummy for the evaluation */
         node->validity |= LYD_VAL_INUSE;
-        rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, &set, LYXP_WHEN);
+        rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
+                       &set, LYXP_WHEN);
         node->validity &= ~LYD_VAL_INUSE;
         if (rc) {
             if (rc == 1) {
@@ -5824,15 +5736,20 @@
         }
 
         /* set boolean result of the condition */
-        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
+        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
         if (!set.val.bool) {
-            LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
             node->when_status |= LYD_WHEN_FALSE;
-            goto cleanup;
+            if (ignore_fail) {
+                LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
+                       ((struct lys_node_container *)node->schema)->when->cond);
+            } else {
+                LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
+                goto cleanup;
+            }
         }
 
         /* free xpath set content */
-        lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
+        lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
     }
 
     sparent = node->schema;
@@ -5857,7 +5774,8 @@
                 goto cleanup;
             }
 
-            rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
+            rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
+                           &set, LYXP_WHEN);
 
             if (unlinked_nodes && ctx_node) {
                 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
@@ -5873,15 +5791,20 @@
                 goto cleanup;
             }
 
-            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
+            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
             if (!set.val.bool) {
-                LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
                 node->when_status |= LYD_WHEN_FALSE;
-                goto cleanup;
+                if (ignore_fail) {
+                    LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
+                        ((struct lys_node_uses *)sparent)->when->cond);
+                } else {
+                    LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
+                    goto cleanup;
+                }
             }
 
             /* free xpath set content */
-            lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
+            lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
         }
 
 check_augment:
@@ -5901,7 +5824,8 @@
                 goto cleanup;
             }
 
-            rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
+            rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
+                           lys_node_module(sparent->parent), &set, LYXP_WHEN);
 
             /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
              * so the tree did not actually change and there is nothing for us to do
@@ -5920,16 +5844,21 @@
                 goto cleanup;
             }
 
-            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
+            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
 
             if (!set.val.bool) {
-                LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
                 node->when_status |= LYD_WHEN_FALSE;
-               goto cleanup;
+                if (ignore_fail) {
+                    LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
+                        ((struct lys_node_augment *)sparent->parent)->when->cond);
+                } else {
+                    LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
+                    goto cleanup;
+                }
             }
 
             /* free xpath set content */
-            lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
+            lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
         }
 
         sparent = lys_parent(sparent);
@@ -5939,7 +5868,7 @@
 
 cleanup:
     /* free xpath set content */
-    lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
+    lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
 
     if (result) {
         if (node->when_status & LYD_WHEN_TRUE) {
@@ -6778,20 +6707,111 @@
     }
 }
 
-int
-resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
+/**
+ * @brief Resolve instance-identifier in JSON data format. Logs directly.
+ *
+ * @param[in] data Data node where the path is used
+ * @param[in] path Instance-identifier node value.
+ * @param[in,out] ret Resolved instance or NULL.
+ *
+ * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
+ */
+static int
+resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
+{
+    int i = 0, j;
+    const struct lys_module *mod;
+    struct ly_ctx *ctx = data->schema->module->ctx;
+    const char *model, *name;
+    char *str;
+    int mod_len, name_len, has_predicate;
+    struct unres_data node_match;
+
+    memset(&node_match, 0, sizeof node_match);
+    *ret = NULL;
+
+    /* we need root to resolve absolute path */
+    for (; data->parent; data = data->parent);
+    /* we're still parsing it and the pointer is not correct yet */
+    if (data->prev) {
+        for (; data->prev->next; data = data->prev);
+    }
+
+    /* search for the instance node */
+    while (path[i]) {
+        j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
+        if (j <= 0) {
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
+            goto error;
+        }
+        i += j;
+
+        str = strndup(model, mod_len);
+        if (!str) {
+            LOGMEM;
+            goto error;
+        }
+        mod = ly_ctx_get_module(ctx, str, NULL);
+        free(str);
+
+        if (resolve_data(mod, name, name_len, data, &node_match)) {
+            /* no instance exists */
+            break;
+        }
+
+        if (has_predicate) {
+            /* we have predicate, so the current results must be list or leaf-list */
+            j = resolve_predicate(&path[i], &node_match);
+            if (j < 1) {
+                LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
+                goto error;
+            }
+            i += j;
+
+            if (!node_match.count) {
+                /* no instance exists */
+                break;
+            }
+        }
+    }
+
+    if (!node_match.count) {
+        /* no instance exists */
+        if (req_inst > -1) {
+            LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
+            return EXIT_FAILURE;
+        }
+        LOGVRB("There is no instance of \"%s\", but it is not required.", path);
+        return EXIT_SUCCESS;
+    } else if (node_match.count > 1) {
+        /* instance identifier must resolve to a single node */
+        LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
+        goto error;
+    } else {
+        /* we have required result, remember it and cleanup */
+        *ret = node_match.node[0];
+        free(node_match.node);
+        return EXIT_SUCCESS;
+    }
+
+error:
+    /* cleanup */
+    free(node_match.node);
+    return -1;
+}
+
+static int
+resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
 {
     struct unres_data matches;
     uint32_t i;
 
-    assert(type->base == LY_TYPE_LEAFREF);
-
     /* init */
-    leaf->value.leafref = NULL;
     memset(&matches, 0, sizeof matches);
+    *ret = NULL;
 
     /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
-    if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
+    if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
         return -1;
     }
 
@@ -6801,58 +6821,143 @@
          * so we can simply compare just the values */
         if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
             /* we have the match */
-            leaf->value.leafref = matches.node[i];
+            *ret = matches.node[i];
             break;
         }
     }
 
     free(matches.node);
 
-    if (!leaf->value.leafref) {
+    if (!*ret) {
         /* reference not found */
-        if (type->info.lref.req > -1) {
-            LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
+        if (req_inst > -1) {
+            LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
             return EXIT_FAILURE;
         } else {
-            LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
+            LOGVRB("There is no leafref \"%s\" with the value \"%s\", but it is not required.", path, leaf->value_str);
         }
     }
 
     return EXIT_SUCCESS;
 }
 
-API const struct lys_type *
-lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve)
-{
-    if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
-        return NULL;
-    }
-    if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_BITS) {
-        free(leaf->value.bit);
-    }
-    memset(&leaf->value, 0, sizeof leaf->value);
-
-    /* resolve */
-    return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
-                           (struct lyd_node *)leaf, leaf, resolve, 1, 0);
-}
-
+/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
 static int
-resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
+resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int ignore_fail)
 {
-    struct lys_type *datatype = NULL;
+    struct lys_type *t;
+    struct lyd_node *ret;
+    int found, hidden, success = 0;
+    const char *json_val = NULL;
 
     assert(type->base == LY_TYPE_UNION);
 
+    if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
+        /* either NULL or instid previously converted to JSON */
+        json_val = leaf->value.string;
+    }
     memset(&leaf->value, 0, sizeof leaf->value);
-    datatype = lyp_parse_value(type, &leaf->value_str, NULL, (struct lyd_node *)leaf, leaf, 1, 1, 0);
-    if (!datatype) {
-        /* failure */
-        LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
+
+    /* turn logging off, we are going to try to validate the value with all the types in order */
+    hidden = *ly_vlog_hide_location();
+    ly_vlog_hide(1);
+
+    t = NULL;
+    found = 0;
+    while ((t = lyp_get_next_union_type(type, t, &found))) {
+        found = 0;
+
+        switch (t->base) {
+        case LY_TYPE_LEAFREF:
+            if (!resolve_leafref(leaf, t->info.lref.path, (ignore_fail ? -1 : t->info.lref.req), &ret)) {
+                if (ret) {
+                    /* valid resolved */
+                    leaf->value.leafref = ret;
+                    leaf->value_type = LY_TYPE_LEAFREF;
+                } else {
+                    /* valid unresolved */
+                    if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
+                        return -1;
+                    }
+                }
+
+                success = 1;
+            }
+            break;
+        case LY_TYPE_INST:
+            if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str),
+                                (ignore_fail ? -1 : t->info.inst.req), &ret)) {
+                if (ret) {
+                    /* valid resolved */
+                    leaf->value.instance = ret;
+                    leaf->value_type = LY_TYPE_INST;
+
+                    if (json_val) {
+                        lydict_remove(leaf->schema->module->ctx, leaf->value_str);
+                        leaf->value_str = json_val;
+                        json_val = NULL;
+                    }
+                } else {
+                    /* valid unresolved */
+                    if (json_val) {
+                        /* put the JSON val back */
+                        leaf->value.string = json_val;
+                        json_val = NULL;
+                    } else {
+                        leaf->value.instance = NULL;
+                    }
+                    leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
+                }
+
+                success = 1;
+            }
+            break;
+        default:
+            if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
+                success = 1;
+            }
+            break;
+        }
+
+        if (success) {
+            break;
+        }
+
+        /* erase information about errors - they are false or irrelevant
+         * and will be replaced by a single error messages */
+        ly_err_clean(1);
+
+        /* erase possible present and invalid value data */
+        if (t->base == LY_TYPE_BITS) {
+            free(leaf->value.bit);
+        }
+        memset(&leaf->value, 0, sizeof leaf->value);
+    }
+
+    /* turn logging back on */
+    if (!hidden) {
+        ly_vlog_hide(0);
+    }
+
+    if (json_val) {
+        if (!success) {
+            /* put the value back for now */
+            assert(leaf->value_type == LY_TYPE_UNION);
+            leaf->value.string = json_val;
+        } else {
+            /* value was ultimately useless, but we could not have known */
+            lydict_remove(leaf->schema->module->ctx, json_val);
+        }
+    }
+
+    if (!success && (!ignore_fail || !type->info.uni.has_ptr_type)) {
+        /* not found and it is required */
+        LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
         return EXIT_FAILURE;
     }
 
     return EXIT_SUCCESS;
+
 }
 
 /**
@@ -6860,14 +6965,16 @@
  *
  * @param[in] node Data node to resolve.
  * @param[in] type Type of the unresolved item.
+ * @param[in] ignore_fails Flag whether to ignore any false condition or unresolved nodes (e.g., for LYD_OPT_EDIT).
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 int
-resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
+resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
 {
-    int rc;
+    int rc, req_inst;
     struct lyd_node_leaf_list *leaf;
+    struct lyd_node *ret;
     struct lys_node_leaf *sleaf;
 
     leaf = (struct lyd_node_leaf_list *)node;
@@ -6876,42 +6983,65 @@
     switch (type) {
     case UNRES_LEAFREF:
         assert(sleaf->type.base == LY_TYPE_LEAFREF);
-        return resolve_leafref(leaf, &sleaf->type);
+        assert(leaf->validity & LYD_VAL_LEAFREF);
+        req_inst = (ignore_fail ? -1 : sleaf->type.info.lref.req);
+        rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
+        if (!rc) {
+            if (ret) {
+                /* valid resolved */
+                leaf->value.leafref = ret;
+                leaf->value_type = LY_TYPE_LEAFREF;
+            } else {
+                /* valid unresolved */
+                if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
+                    if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
+                        return -1;
+                    }
+                }
+            }
+            leaf->validity &= ~LYD_VAL_LEAFREF;
+        } else {
+            return rc;
+        }
+        break;
 
     case UNRES_INSTID:
         assert(sleaf->type.base == LY_TYPE_INST);
-        ly_err_clean(1);
-        leaf->value.instance = resolve_instid(node, leaf->value_str);
-        if (!leaf->value.instance) {
-            if (ly_errno) {
-                return -1;
-            } else if (sleaf->type.info.inst.req > -1) {
-                LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
-                return EXIT_FAILURE;
+        req_inst = (ignore_fail ? -1 : sleaf->type.info.inst.req);
+        rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
+        if (!rc) {
+            if (ret) {
+                /* valid resolved */
+                leaf->value.instance = ret;
+                leaf->value_type = LY_TYPE_INST;
             } else {
-                LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
+                /* valid unresolved */
+                leaf->value.instance = NULL;
+                leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
             }
+        } else {
+            return rc;
         }
         break;
 
     case UNRES_UNION:
         assert(sleaf->type.base == LY_TYPE_UNION);
-        return resolve_union(leaf, &sleaf->type);
+        return resolve_union(leaf, &sleaf->type, ignore_fail);
 
     case UNRES_WHEN:
-        if ((rc = resolve_when(node, NULL))) {
+        if ((rc = resolve_when(node, NULL, ignore_fail))) {
             return rc;
         }
         break;
 
     case UNRES_MUST:
-        if ((rc = resolve_must(node, 0))) {
+        if ((rc = resolve_must(node, 0, ignore_fail))) {
             return rc;
         }
         break;
 
     case UNRES_MUST_INOUT:
-        if ((rc = resolve_must(node, 1))) {
+        if ((rc = resolve_must(node, 1, ignore_fail))) {
             return rc;
         }
         break;
@@ -6979,9 +7109,9 @@
 resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
 {
     uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
-    int rc, progress;
+    int rc, progress, ignore_fails;
     struct lyd_node *parent;
-    struct lyd_node_leaf_list *leaf;
+    //struct lyd_node_leaf_list *leaf;
 
     assert(root);
     assert(unres);
@@ -6990,6 +7120,12 @@
         return EXIT_SUCCESS;
     }
 
+    if (options & (LYD_OPT_TRUSTED | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
+        ignore_fails = 1;
+    } else {
+        ignore_fails = 0;
+    }
+
     LOGVRB("Resolving unresolved data nodes and their constraints...");
     ly_vlog_hide(1);
 
@@ -7001,7 +7137,6 @@
             if (unres->type[i] != UNRES_WHEN) {
                 continue;
             }
-            assert(!(options & LYD_OPT_TRUSTED));
             if (first) {
                 /* count when-stmt nodes in unres list */
                 when_stmt++;
@@ -7025,7 +7160,7 @@
                 continue;
             }
 
-            rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
+            rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
             if (!rc) {
                 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
                     if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
@@ -7089,7 +7224,7 @@
             } else if (rc == -1) {
                 ly_vlog_hide(0);
                 /* print only this last error */
-                resolve_unres_data_item(unres->node[i], unres->type[i]);
+                resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
                 return -1;
             } /* else forward reference */
         }
@@ -7119,6 +7254,7 @@
         unres->type[i] = UNRES_RESOLVED;
         del_items--;
     }
+    ly_vlog_hide(0);
 
     /* rest */
     for (i = 0; i < unres->count; ++i) {
@@ -7127,47 +7263,37 @@
         }
         assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
 
-        rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
-        if (rc == -1) {
-            ly_vlog_hide(0);
+        rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
+        if (rc) {
+            /* since when was already resolved, a forward reference is an error */
+            //ly_vlog_hide(0);
             /* print only this last error */
-            resolve_unres_data_item(unres->node[i], unres->type[i]);
+            //resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
             return -1;
-        } else if ((rc == 0) || ((options & LYD_OPT_TRUSTED) && ((unres->type[i] == UNRES_LEAFREF) || (unres->type[i] == UNRES_INSTID)))) {
-            unres->type[i] = UNRES_RESOLVED;
-            resolved++;
-            if (options & LYD_OPT_TRUSTED) {
-                /* accept it in this case */
-                if (unres->type[i] == UNRES_LEAFREF) {
-                    LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
-                           ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
-                           ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
-                } else {
-                    LOGVRB("Instance identifier \"%s\" failed to be resolved.",
-                           ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
-                }
-            }
         }
+
+        unres->type[i] = UNRES_RESOLVED;
+        //resolved++;
     }
 
-    ly_vlog_hide(0);
-    if (resolved < unres->count) {
+    //ly_vlog_hide(0);
+    //if (resolved < unres->count) {
         /* try to resolve the unresolved data again, it will not resolve anything, but it will print
          * all the validation errors
          */
-        for (i = 0; i < unres->count; ++i) {
-            if (unres->type[i] == UNRES_UNION) {
+        //for (i = 0; i < unres->count; ++i) {
+            //if (unres->type[i] == UNRES_UNION) {
                 /* does not make sense to print specific errors for all
                  * the data types, just print that the value is invalid */
-                leaf = (struct lyd_node_leaf_list *)unres->node[i];
+                /*leaf = (struct lyd_node_leaf_list *)unres->node[i];
                 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
                        leaf->schema->name);
             } else if (unres->type[i] != UNRES_RESOLVED) {
-                resolve_unres_data_item(unres->node[i], unres->type[i]);
+                resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fails);
             }
         }
         return -1;
-    }
+    }*/
 
     LOGVRB("All data nodes and constraints resolved.");
     unres->count = 0;
diff --git a/src/resolve.h b/src/resolve.h
index ef7f848..335be38 100644
--- a/src/resolve.h
+++ b/src/resolve.h
@@ -175,12 +175,10 @@
 int resolve_applies_must(const struct lyd_node *node);
 
 struct lys_ident *resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node);
-struct lyd_node *resolve_instid(struct lyd_node *data, const char *path);
-int resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type);
 
 int resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres);
 
-int resolve_when(struct lyd_node *node, int *result);
+int resolve_when(struct lyd_node *node, int *result, int ignore_fail);
 
 int unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
                          const char *str);
@@ -199,7 +197,7 @@
 
 void unres_schema_free(struct lys_module *module, struct unres_schema **unres);
 
-int resolve_unres_data_item(struct lyd_node *dnode, enum UNRES_ITEM type);
+int resolve_unres_data_item(struct lyd_node *dnode, enum UNRES_ITEM type, int ignore_fails);
 
 int unres_data_addonly(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type);
 int unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type);
diff --git a/src/tree_data.c b/src/tree_data.c
index b062ed4..410b5f8 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -106,7 +106,7 @@
                 }
                 for (current = dummy; current; current = current->child) {
                     ly_vlog_hide(1);
-                    resolve_when(current, &state);
+                    resolve_when(current, &state, 0);
                     ly_vlog_hide(0);
                     if (!state) {
                         /* when evaluates to false */
@@ -608,7 +608,7 @@
         return NULL;
     }
     ret->schema = (struct lys_node *)schema;
-    ret->validity = LYD_VAL_NOT;
+    ret->validity = ly_new_node_validity(schema);
     if (resolve_applies_when(schema, 0, NULL)) {
         ret->when_status = LYD_WHEN;
     }
@@ -659,7 +659,7 @@
         return NULL;
     }
     ret->schema = (struct lys_node *)schema;
-    ret->validity = LYD_VAL_NOT;
+    ret->validity = ly_new_node_validity(schema);
     if (resolve_applies_when(schema, 0, NULL)) {
         ret->when_status = LYD_WHEN;
     }
@@ -687,13 +687,11 @@
             lyd_free(ret);
             return NULL;
         }
-
-        /* update default flags */
     }
 
     /* resolve the type correctly (after it was connected to parent cause of log) */
     if (!lyp_parse_value(&((struct lys_node_leaf *)ret->schema)->type, &((struct lyd_node_leaf_list *)ret)->value_str,
-                         NULL, NULL, (struct lyd_node_leaf_list *)ret, 1, 1, 0)) {
+                         NULL, (struct lyd_node_leaf_list *)ret, 1, 0)) {
         lyd_free(ret);
         return NULL;
     }
@@ -735,6 +733,83 @@
     return _lyd_new_leaf(parent, snode, val_str, 0);
 }
 
+static void
+lyd_wd_update_parents(struct lyd_node *node)
+{
+    struct lyd_node *parent = node->parent, *iter;
+
+    for (parent = node->parent; parent; parent = node->parent) {
+        if (parent->dflt || parent->schema->nodetype != LYS_CONTAINER ||
+                ((struct lys_node_container *)parent->schema)->presence) {
+            /* parent is already default and there is nothing to update or
+             * it is not a non-presence container -> stop the loop */
+            break;
+        }
+        /* check that there is still some non default sibling */
+        for (iter = node->prev; iter != node; iter = iter->prev) {
+            if (!iter->dflt) {
+                break;
+            }
+        }
+        if (iter == node && node->prev != node) {
+            /* all siblings are implicit default nodes, propagate it to the parent */
+            node = node->parent;
+            node->dflt = 1;
+            continue;
+        } else {
+            /* stop the loop */
+            break;
+        }
+    }
+}
+
+
+/* op - 0 add, 1 del, 2 mod (add + del) */
+static void
+check_leaf_list_backlinks(struct lyd_node *node, int op)
+{
+    struct lyd_node *next, *iter;
+    struct lyd_node_leaf_list *leaf_list;
+    struct ly_set *set, *data;
+    uint32_t i, j;
+
+    assert((op == 0) || (op == 1) || (op == 2));
+
+    /* fix leafrefs */
+    LY_TREE_DFS_BEGIN(node, next, iter) {
+        /* the node is target of a leafref */
+        if ((iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && iter->schema->child) {
+            set = (struct ly_set *)iter->schema->child;
+            for (i = 0; i < set->number; i++) {
+                data = lyd_find_instance(iter, set->set.s[i]);
+                if (data) {
+                    for (j = 0; j < data->number; j++) {
+                        leaf_list = (struct lyd_node_leaf_list *)data->set.d[j];
+                        if (((op != 0) && (leaf_list->value_type == LY_TYPE_LEAFREF) && (leaf_list->value.leafref == iter))
+                                || ((op != 1) && (leaf_list->value_type & LY_TYPE_LEAFREF_UNRES))) {
+                            /* invalidate the leafref, a change concerning it happened */
+                            leaf_list->validity |= LYD_VAL_LEAFREF;
+                        }
+                    }
+                    ly_set_free(data);
+                } else {
+                    LOGINT;
+                    return;
+                }
+            }
+        }
+        LY_TREE_DFS_END(node, next, iter)
+    }
+
+    /* invalidate parent to make sure it will be checked in future validation */
+    if (node->parent) {
+        node->parent->validity = LYD_VAL_MAND;
+    }
+
+    /* update parent's default flag if needed */
+    lyd_wd_update_parents(node);
+}
+
 API int
 lyd_change_leaf(struct lyd_node_leaf_list *leaf, const char *val_str)
 {
@@ -772,9 +847,8 @@
     leaf->value_str = lydict_insert(leaf->schema->module->ctx, val_str ? val_str : "", 0);
     /* leaf->value is erased by lyp_parse_value() */
 
-    /* resolve the type correctly, makes the value canonical if needed */
-    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, (struct lyd_node *)leaf,
-            leaf, 1, 1, 0)) {
+    /* parse the type correctly, makes the value canonical if needed */
+    if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL, leaf, 1, 0)) {
         lydict_remove(leaf->schema->module->ctx, leaf->value_str);
         leaf->value_str = backup;
         memcpy(&leaf->value, &backup_val, sizeof backup);
@@ -790,6 +864,14 @@
     /* clear the default flag, the value is different */
     leaf->dflt = 0;
 
+    /* make the leafref unresolved */
+    if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_LEAFREF) {
+        leaf->validity |= LYD_VAL_LEAFREF;
+    }
+
+    /* check possible leafref backlinks */
+    check_leaf_list_backlinks((struct lyd_node *)leaf, 2);
+
     if (leaf->schema->flags & LYS_UNIQUE) {
         /* locate the first parent list */
         for (parent = leaf->parent; parent && parent->schema->nodetype != LYS_LIST; parent = parent->parent);
@@ -816,7 +898,7 @@
         return NULL;
     }
     ret->schema = (struct lys_node *)schema;
-    ret->validity = LYD_VAL_NOT;
+    ret->validity = ly_new_node_validity(schema);
     if (resolve_applies_when(schema, 0, NULL)) {
         ret->when_status = LYD_WHEN;
     }
@@ -1537,12 +1619,13 @@
 
         trg_leaf->value = src_leaf->value;
         src_leaf->value = (lyd_val)0;
-        if ((trg_leaf->value_type == LY_TYPE_INST) || (trg_leaf->value_type == LY_TYPE_LEAFREF)) {
-            /* these are, for instance, cases when the resulting data tree will definitely not be valid */
-            trg_leaf->value = (lyd_val)0;
+        if (trg_leaf->value_type == LY_TYPE_LEAFREF) {
+            trg_leaf->validity |= LYD_VAL_LEAFREF;
         }
 
         trg_leaf->dflt = src_leaf->dflt;
+
+        check_leaf_list_backlinks(target, 2);
     } else {
         trg_any = (struct lyd_node_anydata *)target;
         src_any = (struct lyd_node_anydata *)source;
@@ -2715,9 +2798,9 @@
     assert(node);
 
     /* overall validity of the node itself */
-    node->validity = LYD_VAL_NOT;
+    node->validity = ly_new_node_validity(node->schema);
 
-    /* explore changed unique leafs */
+    /* explore changed unique leaves */
     /* first, get know if there is a list in parents chain */
     for (parent_list = node->parent;
          parent_list && parent_list->schema->nodetype != LYS_LIST;
@@ -2854,16 +2937,11 @@
     return EXIT_SUCCESS;
 }
 
-API int
+static void
 lyd_replace(struct lyd_node *orig, struct lyd_node *repl, int destroy)
 {
     struct lyd_node *iter, *last;
 
-    if (!orig) {
-        ly_errno = LY_EINVAL;
-        return EXIT_FAILURE;
-    }
-
     if (!repl) {
         /* remove the old one */
         goto finish;
@@ -2922,7 +3000,6 @@
     if (destroy) {
         lyd_free(orig);
     }
-    return EXIT_SUCCESS;
 }
 
 static int
@@ -3135,6 +3212,8 @@
         }
         ins->parent = parent;
 
+        check_leaf_list_backlinks(ins, 0);
+
         if (invalid) {
             lyd_insert_setinvalid(ins);
         }
@@ -3342,6 +3421,14 @@
         node->prev = sibling;
     }
 
+    LY_TREE_FOR(node, next1) {
+        check_leaf_list_backlinks(next1, 0);
+        if (next1 == last) {
+            break;
+        }
+    }
+
+
     return EXIT_SUCCESS;
 
 error:
@@ -3553,22 +3640,6 @@
 }
 
 API int
-lyd_validate_leafref(struct lyd_node_leaf_list *leafref)
-{
-    if (!leafref || leafref->value_type != LY_TYPE_LEAFREF) {
-        ly_errno = LY_EINVAL;
-        return EXIT_FAILURE;
-    }
-
-    if (leafref->value.leafref) {
-        /* nothing to do */
-        return EXIT_SUCCESS;
-    }
-
-    return resolve_unres_data_item((struct lyd_node *)leafref, UNRES_LEAFREF);
-}
-
-API int
 lyd_validate(struct lyd_node **node, int options, void *var_arg)
 {
     struct lyd_node *root, *next1, *next2, *iter, *act_notif = NULL, *to_free = NULL, *data_tree = NULL;
@@ -3641,7 +3712,7 @@
     if ((options & (LYD_OPT_RPC | LYD_OPT_RPCREPLY)) && *node && ((*node)->schema->nodetype != LYS_RPC)) {
         options |= LYD_OPT_ACT_NOTIF;
     }
-    if ((options & LYD_OPT_NOTIF) && *node && ((*node)->schema->nodetype != LYS_NOTIF)) {
+    if ((options & (LYD_OPT_NOTIF | LYD_OPT_NOTIF_FILTER)) && *node && ((*node)->schema->nodetype != LYS_NOTIF)) {
         options |= LYD_OPT_ACT_NOTIF;
     }
 
@@ -3676,12 +3747,8 @@
                 }
             }
 
-            /* validation successful */
-            if (iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
-                iter->validity &= LYD_VAL_UNIQUE;
-            } else {
-                iter->validity = LYD_VAL_OK;
-            }
+            /* basic validation successful */
+            iter->validity &= ~LYD_VAL_MAND;
 
             /* where go next? - modified LY_TREE_DFS_END */
             if (iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
@@ -3829,42 +3896,10 @@
     return ret;
 }
 
-static void
-lyd_wd_update_parents(struct lyd_node *node)
-{
-    struct lyd_node *parent = node->parent, *iter;
-
-    for (parent = node->parent; parent; parent = node->parent) {
-        if (parent->dflt || parent->schema->nodetype != LYS_CONTAINER ||
-                ((struct lys_node_container *)parent->schema)->presence) {
-            /* parent is already default and there is nothing to update or
-             * it is not a non-presence container -> stop the loop */
-            break;
-        }
-        /* check that there is still some non default sibling */
-        for (iter = node->prev; iter != node; iter = iter->prev) {
-            if (!iter->dflt) {
-                break;
-            }
-        }
-        if (iter == node && node->prev != node) {
-            /* all siblings are implicit default nodes, propagate it to the parent */
-            node = node->parent;
-            node->dflt = 1;
-            continue;
-        } else {
-            /* stop the loop */
-            break;
-        }
-    }
-}
-
 static int
 lyd_unlink_internal(struct lyd_node *node, int permanent)
 {
-    struct lyd_node *iter, *next;
-    struct ly_set *set, *data;
-    unsigned int i, j;
+    struct lyd_node *iter;
 
     if (!node) {
         ly_errno = LY_EINVAL;
@@ -3872,36 +3907,7 @@
     }
 
     if (permanent) {
-        /* fix leafrefs */
-        LY_TREE_DFS_BEGIN(node, next, iter) {
-            /* the node is target of a leafref */
-            if ((iter->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && iter->schema->child) {
-                set = (struct ly_set *)iter->schema->child;
-                for (i = 0; i < set->number; i++) {
-                    data = lyd_find_instance(iter, set->set.s[i]);
-                    if (data) {
-                        for (j = 0; j < data->number; j++) {
-                            if (((struct lyd_node_leaf_list *)data->set.d[j])->value.leafref == iter) {
-                                /* remove reference to the node we are going to replace */
-                                ((struct lyd_node_leaf_list *)data->set.d[j])->value.leafref = NULL;
-                            }
-                        }
-                        ly_set_free(data);
-                    } else {
-                        return EXIT_FAILURE;
-                    }
-                }
-            }
-            LY_TREE_DFS_END(node, next, iter)
-        }
-
-        /* invalidate parent to make sure it will be checked in future validation */
-        if (node->parent) {
-            node->parent->validity = LYD_VAL_MAND;
-        }
-
-        /* update parent's default flag if needed */
-        lyd_wd_update_parents(node);
+        check_leaf_list_backlinks(node, 1);
     }
 
     /* unlink from siblings */
@@ -4077,7 +4083,7 @@
         new_node->next = NULL;
         new_node->prev = new_node;
         new_node->parent = NULL;
-        new_node->validity = LYD_VAL_NOT;
+        new_node->validity = ly_new_node_validity(new_node->schema);
         new_node->dflt = elem->dflt;
         new_node->when_status = elem->when_status & LYD_WHEN;
 
@@ -4290,11 +4296,16 @@
             if (((struct lyd_node_leaf_list *)node)->value.bit) {
                 free(((struct lyd_node_leaf_list *)node)->value.bit);
             }
-            /* fallthrough */
+            break;
+        case LY_TYPE_UNION:
+            /* unresolved union leaf */
+            lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value.string);
+            break;
         default:
-            lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value_str);
             break;
         }
+
+        lydict_remove(node->schema->module->ctx, ((struct lyd_node_leaf_list *)node)->value_str);
     }
 
     lyd_unlink(node);
@@ -4710,7 +4721,7 @@
 
     memset(&xp_set, 0, sizeof xp_set);
 
-    if (lyxp_eval(expr, data, LYXP_NODE_ELEM, &xp_set, 0) != EXIT_SUCCESS) {
+    if (lyxp_eval(expr, data, LYXP_NODE_ELEM, lyd_node_module(data), &xp_set, 0) != EXIT_SUCCESS) {
         return NULL;
     }
 
@@ -4732,7 +4743,7 @@
         }
     }
     /* free xp_set content */
-    lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, data, 0);
+    lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, data, NULL, 0);
 
     return set;
 }
@@ -5103,8 +5114,7 @@
 }
 
 static int
-lyd_wd_add_leaf(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaf *leaf, int options,
-                struct unres_data *unres)
+lyd_wd_add_leaf(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaf *leaf, struct unres_data *unres)
 {
     struct lyd_node *dummy = NULL, *current;
     struct lys_tpdf *tpdf;
@@ -5137,19 +5147,16 @@
         }
     }
     for (current = dummy; ; current = current->child) {
-        /* if necessary, remember the created data in unres */
-        if (!(options & LYD_OPT_TRUSTED) && (!(options & LYD_OPT_TYPEMASK)
-                || (options & (LYD_OPT_CONFIG | LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)))) {
-            if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
-                goto error;
-            }
-            ret = resolve_applies_must(current);
-            if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
-                goto error;
-            }
-            if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
-                goto error;
-            }
+        /* remember the created data in unres */
+        if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
+            goto error;
+        }
+        ret = resolve_applies_must(current);
+        if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
+            goto error;
+        }
+        if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
+            goto error;
         }
 
         /* clear dummy-node flag */
@@ -5184,8 +5191,7 @@
 }
 
 static int
-lyd_wd_add_leaflist(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaflist *llist, int options,
-                    struct unres_data *unres)
+lyd_wd_add_leaflist(struct lyd_node **tree, struct lyd_node *last_parent, struct lys_node_leaflist *llist, struct unres_data *unres)
 {
     struct lyd_node *dummy, *current, *first = NULL;
     struct lys_tpdf *tpdf;
@@ -5235,19 +5241,16 @@
         }
 
         for (current = dummy; ; current = current->child) {
-            /* if necessary, remember the created data in unres */
-            if (!(options & LYD_OPT_TRUSTED) && (!(options & LYD_OPT_TYPEMASK)
-                    || (options & (LYD_OPT_CONFIG | LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)))) {
-                if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
-                    goto error;
-                }
-                ret = resolve_applies_must(current);
-                if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
-                    goto error;
-                }
-                if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
-                    goto error;
-                }
+            /* remember the created data in unres */
+            if ((current->when_status & LYD_WHEN) && unres_data_add(unres, current, UNRES_WHEN) == -1) {
+                goto error;
+            }
+            ret = resolve_applies_must(current);
+            if ((ret & 0x1) && (unres_data_add(unres, current, UNRES_MUST) == -1)) {
+                goto error;
+            }
+            if ((ret & 0x2) && (unres_data_add(unres, current, UNRES_MUST_INOUT) == -1)) {
+                goto error;
             }
 
             /* clear dummy-node flag */
@@ -5399,19 +5402,16 @@
             }
             last_parent = subroot;
 
-            if (!(options & LYD_OPT_TRUSTED) && (!(options & LYD_OPT_TYPEMASK)
-                    || (options & (LYD_OPT_CONFIG | LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)))) {
-                /* if necessary, remember the created container in unres */
-                if ((subroot->when_status & LYD_WHEN) && unres_data_add(unres, subroot, UNRES_WHEN) == -1) {
-                    goto error;
-                }
-                i = resolve_applies_must(subroot);
-                if ((i & 0x1) && (unres_data_add(unres, subroot, UNRES_MUST) == -1)) {
-                    goto error;
-                }
-                if ((i & 0x2) && (unres_data_add(unres, subroot, UNRES_MUST_INOUT) == -1)) {
-                    goto error;
-                }
+            /* remember the created container in unres */
+            if ((subroot->when_status & LYD_WHEN) && unres_data_add(unres, subroot, UNRES_WHEN) == -1) {
+                goto error;
+            }
+            i = resolve_applies_must(subroot);
+            if ((i & 0x1) && (unres_data_add(unres, subroot, UNRES_MUST) == -1)) {
+                goto error;
+            }
+            if ((i & 0x2) && (unres_data_add(unres, subroot, UNRES_MUST_INOUT) == -1)) {
+                goto error;
             }
         }
         /* no break */
@@ -5474,11 +5474,11 @@
             }
         }
         if (schema->nodetype == LYS_LEAF) {
-            if (lyd_wd_add_leaf(root, last_parent, (struct lys_node_leaf*)schema, options, unres)) {
+            if (lyd_wd_add_leaf(root, last_parent, (struct lys_node_leaf*)schema, unres)) {
                 return EXIT_FAILURE;
             }
         } else { /* LYS_LEAFLIST */
-            if (lyd_wd_add_leaflist(root, last_parent, (struct lys_node_leaflist*)schema, options, unres)) {
+            if (lyd_wd_add_leaflist(root, last_parent, (struct lys_node_leaflist*)schema, unres)) {
                 goto error;
             }
         }
@@ -5808,3 +5808,14 @@
 
     return atof(((struct lyd_node_leaf_list *)node)->value_str);
 }
+
+API const struct lys_type *
+lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
+{
+    if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
+        return NULL;
+    }
+
+    return lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, (const char **)&leaf->value_str, NULL,
+                           (struct lyd_node_leaf_list *)leaf, 0, 0);
+}
diff --git a/src/tree_data.h b/src/tree_data.h
index bd51c08..4f79214 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -132,14 +132,18 @@
  *
  * @{
  */
-#define LYD_VAL_OK       0x00    /**< node is successfully validated including whole subtree */
+#define LYD_VAL_OK       0x00    /**< Node is successfully validated including whole subtree */
 #define LYD_VAL_UNIQUE   0x01    /**< Unique value(s) changed, applicable only to ::lys_node_list data nodes */
 #define LYD_VAL_MAND     0x02    /**< Some child added/removed and it is needed to perform check for mandatory
                                       node or min/max constraints of direct list/leaflist children, applicable only
-                                      to ::lys_node_list and ::lys_node_container data nodes */
-#define LYD_VAL_NOT      0x07    /**< node was not validated yet */
-#define LYD_VAL_INUSE    0x08    /**< Internal flag for note about various processing on data, should be used only
-                                      internally and removed before the libyang returns to the caller */
+                                      to ::lys_node_list and ::lys_node_container data nodes, but if on any other node
+                                      except ::lys_node_leaflist, it means checking that data node for duplicities.
+                                      Additionally, it can be set on truly any node type and then status references
+                                      are checked for this node if flag #LYD_OPT_OBSOLETE is used. */
+#define LYD_VAL_LEAFREF  0x04    /**< Node is a leafref, which needs to be resolved (it is invalid, new possible
+                                      resolvent, or something similar) */
+#define LYD_VAL_INUSE    0x80    /**< Internal flag for note about various processing on data, should be used only
+                                      internally and removed before libyang returns the node to the caller */
 /**
  * @}
  */
@@ -158,7 +162,7 @@
  */
 struct lyd_node {
     struct lys_node *schema;         /**< pointer to the schema definition of this node */
-    uint8_t validity:4;              /**< [validity flags](@ref validityflags) */
+    uint8_t validity;                /**< [validity flags](@ref validityflags) */
     uint8_t dflt:1;                  /**< flag for default node */
     uint8_t when_status:3;           /**< bit for checking if the when-stmt condition is resolved - internal use only,
                                           do not use this value! */
@@ -190,7 +194,7 @@
 struct lyd_node_leaf_list {
     struct lys_node *schema;         /**< pointer to the schema definition of this node which is ::lys_node_leaflist
                                           structure */
-    uint8_t validity:4;              /**< [validity flags](@ref validityflags) */
+    uint8_t validity;                /**< [validity flags](@ref validityflags) */
     uint8_t dflt:1;                  /**< flag for default node */
     uint8_t when_status:3;           /**< bit for checking if the when-stmt condition is resolved - internal use only,
                                           do not use this value! */
@@ -224,7 +228,7 @@
 struct lyd_node_anydata {
     struct lys_node *schema;         /**< pointer to the schema definition of this node which is ::lys_node_anydata
                                           structure */
-    uint8_t validity:4;              /**< [validity flags](@ref validityflags) */
+    uint8_t validity;                /**< [validity flags](@ref validityflags) */
     uint8_t dflt:1;                  /**< flag for default node */
     uint8_t when_status:3;           /**< bit for checking if the when-stmt condition is resolved - internal use only,
                                           do not use this value! */
@@ -433,22 +437,25 @@
 #define LYD_OPT_RPC        0x10 /**< Data represents RPC's input parameters. */
 #define LYD_OPT_RPCREPLY   0x20 /**< Data represents RPC's output parameters (maps to NETCONF <rpc-reply> data). */
 #define LYD_OPT_NOTIF      0x40 /**< Data represents an event notification data. */
-/* 0x80 reserved, formerly LYD_OPT_FILTER, now used internally */
+#define LYD_OPT_NOTIF_FILTER 0x80 /**< Data represents a filtered event notification data.
+                                       Validation modification:
+                                       - the only requirement is that the data tree matches the schema tree */
 #define LYD_OPT_TYPEMASK   0xff /**< Mask to filter data type options. Always only a single data type option (only
                                      single bit from the lower 8 bits) can be set. */
 
-#define LYD_OPT_STRICT     0x0100 /**< Instead of silent ignoring data without schema definition, raise an error. */
-#define LYD_OPT_DESTRUCT   0x0200 /**< Free the provided XML tree during parsing the data. With this option, the
+/* 0x100 reserved, used internally */
+#define LYD_OPT_STRICT     0x0200 /**< Instead of silent ignoring data without schema definition, raise an error. */
+#define LYD_OPT_DESTRUCT   0x0400 /**< Free the provided XML tree during parsing the data. With this option, the
                                        provided XML tree is affected and all succesfully parsed data are freed.
                                        This option is applicable only to lyd_parse_xml() function. */
-#define LYD_OPT_OBSOLETE   0x0400 /**< Raise an error when an obsolete statement (status set to obsolete) is used. */
-#define LYD_OPT_NOSIBLINGS 0x0800 /**< Parse only a single XML tree from the input. This option applies only to
+#define LYD_OPT_OBSOLETE   0x0800 /**< Raise an error when an obsolete statement (status set to obsolete) is used. */
+#define LYD_OPT_NOSIBLINGS 0x1000 /**< Parse only a single XML tree from the input. This option applies only to
                                        XML input data. */
-#define LYD_OPT_TRUSTED    0x1000 /**< Data comes from a trusted source and it is not needed to validate them. Data
+#define LYD_OPT_TRUSTED    0x2000 /**< Data comes from a trusted source and it is not needed to validate them. Data
                                        are connected with the schema, but the most validation checks (mandatory nodes,
                                        list instance uniqueness, etc.) are not performed. This option does not make
                                        sense for lyd_validate() so it is ignored by this function. */
-#define LYD_OPT_NOAUTODEL  0x2000 /**< Avoid automatic delete of subtrees with false when-stmt condition. The flag is
+#define LYD_OPT_NOAUTODEL  0x4000 /**< Avoid automatic delete of subtrees with false when-stmt condition. The flag is
                                        applicable only in combination with LYD_OPT_DATA and LYD_OPT_CONFIG flags.
                                        If used, libyang generates validation error instead of silently removing the
                                        constrained subtree. */
@@ -747,7 +754,7 @@
  * @param[in] data_tree Existing data tree to add to/modify. If creating RPCs/actions, there should only be one
  * RPC/action and either input or output, not both. Can be NULL.
  * @param[in] ctx Context to use. Mandatory if \p data_tree is NULL.
- * @param[in] path Simple data XPath of the new node. It can contain only simple node addressing with optional
+ * @param[in] path Simple absolute data XPath of the new node. It can contain only simple node addressing with optional
  * module names as prefixes. List nodes must have predicates, one for each list key in the correct order and
  * with its value as well, leaves and leaf-lists can have predicates too that have preference over \p value,
  * see @ref howtoxpath.
@@ -898,19 +905,6 @@
 int lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node);
 
 /**
- * @brief Insert the \p new element instead of the \p old element.
- *
- * If the \p new is the first node of a node list (with no parent), all the subsequent nodes are also inserted.
- * If the \p new is NULL and \p destroy is true, it works like lyd_free(old).
- *
- * @param[in] orig The specific node in the original tree supposed to be replaced.
- * @param[in] repl The new (list of) node(s) to be inserted instead of \p old
- * @param[in] destroy Flag for freeing the \p old.
- * @return 0 on success, nonzero in case of error.
- */
-int lyd_replace(struct lyd_node *orig, struct lyd_node *repl, int destroy);
-
-/**
  * @brief Order siblings according to the schema node ordering.
  *
  * If the siblings include data nodes from other modules, they are
@@ -960,19 +954,6 @@
 struct lyd_node *lyd_first_sibling(struct lyd_node *node);
 
 /**
- * @brief Resolve the leafref.
- *
- * This function is considered to be a part of a low level API and it should be used deliberately.
- *
- * @param[in] leafref The leafref node to resolve.
- * @return
- * - EXIT_SUCCESS on success,
- * - EXIT_FAILURE when target does not exist,
- * - -1 on error.
- */
-int lyd_validate_leafref(struct lyd_node_leaf_list *leafref);
-
-/**
  * @brief Validate \p node data subtree.
  *
  * @param[in,out] node Data tree to be validated. In case the \p options does not includes #LYD_OPT_NOAUTODEL, libyang
@@ -1078,6 +1059,15 @@
 struct lys_module *lyd_node_module(const struct lyd_node *node);
 
 /**
+ * @brief Get the type structure of a leaf. In case of union, the correct
+ * specific type is found.
+ *
+ * @param[in] leaf Leaf to examine.
+ * @return Type structure of \p leaf, NULL on error.
+ */
+const struct lys_type *lyd_leaf_type(const struct lyd_node_leaf_list *leaf);
+
+/**
 * @brief Print data tree in the specified format.
 *
 * Same as lyd_print(), but it allocates memory and store the data into it.
@@ -1147,22 +1137,6 @@
  */
 double lyd_dec64_to_double(const struct lyd_node *node);
 
-/**
- * @brief Get the real data type definition of the leaf/leaf-list node.
- *
- * Usually the data type can be obtained directly from the value_type member of the leaf/leaf-list.
- * However, in case the node is unresolved leafref or the complete definition of the type is needed, it can be quite
- * complicated to get the correct data type, so this function can be used. The real type describes the value
- * representation so it is not #LY_TYPE_UNION neither #LY_TYPE_LEAFREF.
- *
- * @param[in] leaf The leaf/leaf-list node to be examined.
- * @param[in] resolve Flag to store the leaf's value as its value data, in this case the value is resolved in the data
- *            tree. Otherwise the data tree is not checked, so e.g. leafref type can be returned even if the value
- *            does not match any target value in the data tree.
- * @return Pointer to the type definition of the \p leaf.
- */
-const struct lys_type *lyd_leaf_type(struct lyd_node_leaf_list *leaf, int resolve);
-
 /**@} */
 
 #ifdef __cplusplus
diff --git a/src/tree_internal.h b/src/tree_internal.h
index 49f9371..eda8b7c 100644
--- a/src/tree_internal.h
+++ b/src/tree_internal.h
@@ -61,7 +61,7 @@
 /**
  * @brief internal parser flag for actions and inline notifications
  */
-#define LYD_OPT_ACT_NOTIF 0x80
+#define LYD_OPT_ACT_NOTIF 0x100
 
 /**
  * @brief Internal list of built-in types
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 7aa0551..a7f866c 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1717,9 +1717,9 @@
 {
     int i;
 
-    if (llist->child) {
+    if (llist->backlinks) {
         /* leafref backlinks */
-        ly_set_free((struct ly_set *)llist->child);
+        ly_set_free(llist->backlinks);
     }
 
     for (i = 0; i < llist->must_size; i++) {
@@ -3147,7 +3147,7 @@
             return -1;
         }
     }
-    ly_set_add((struct ly_set *)leafref_target->backlinks, leafref, 0);
+    ly_set_add(leafref_target->backlinks, leafref, 0);
 
     return 0;
 }
@@ -3342,7 +3342,7 @@
     }
 
     LY_TREE_DFS_BEGIN(node, next, elem) {
-        if ((options & LYXP_NO_LOCAL) && !(elem->flags & LYS_VALID_DEP)) {
+        if ((options & LYXP_NO_LOCAL) && !(elem->flags & LYS_XPATH_DEP)) {
             /* elem has no dependencies from other subtrees and local nodes get discarded */
             goto next_iter;
         }
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 6a5b8c4..b9fc8ba 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -479,6 +479,7 @@
 struct lys_type_info_union {
     struct lys_type *types;  /**< array of union's subtypes */
     int count;               /**< number of subtype definitions in types array */
+    int has_ptr_type;       /**< types include an instance-identifier or leafref meaning the union must always be resolved */
 };
 
 /**
@@ -640,9 +641,11 @@
  *       LYS_UNIQUE       | | |x| | | | | | | | | | | | | | | |
  *       LYS_FENABLED     | | | | | | | | | | | | | | |x| | | |
  *                        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *    10 LYS_VALID_DEP    |x|x|x|x|x|x|x|x|x|x|x| |x|x| | | | |
+ *    10 LYS_XPATH_DEP    |x|x|x|x|x|x|x|x|x|x|x| |x|x| | | | |
  *                        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *    11 LYS_DFLTJSON     | | |x|x| | | | | | | | | | | |x| | |
+ *    11 LYS_LeafREF_DEP  |x|x|x|x|x|x|x|x|x|x|x| |x|x| | | | |
+ *                        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *    12 LYS_DFLTJSON     | | |x|x| | | | | | | | | | | |x| | |
  *    --------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * @{
  */
@@ -671,10 +674,13 @@
                                           ::lys_type enum and bits flags */
 #define LYS_USESGRP      0x01        /**< flag for resolving uses in groupings, applicable only to ::lys_node_uses */
 #define LYS_IMPLICIT     0x01        /**< flag for implicitely created LYS_INPUT and LYS_OUTPUT nodes */
-#define LYS_VALID_DEP    0x200       /**< flag marking nodes, whose validation (when, must expressions or leafrefs)
+#define LYS_XPATH_DEP    0x200       /**< flag marking nodes, whose validation (when, must expressions)
                                           depends on nodes outside their subtree (applicable only to RPCs,
                                           notifications, and actions) */
-#define LYS_DFLTJSON     0x400       /**< default value (in ::lys_node_leaf, ::lys_node_leaflist, :lys_tpdf) was
+#define LYS_LEAFREF_DEP  0x400       /**< flag marking nodes, whose validation (leafrefs)
+                                          depends on nodes outside their subtree (applicable only to RPCs,
+                                          notifications, and actions) */
+#define LYS_DFLTJSON     0x800       /**< default value (in ::lys_node_leaf, ::lys_node_leaflist, :lys_tpdf) was
                                           converted into JSON format, since it contains identityref value which is
                                           being used in JSON format (instead of module prefixes, we use the module
                                           names) */
@@ -896,9 +902,9 @@
 
     LYS_NODE nodetype;               /**< type of the node (mandatory) - #LYS_LEAFLIST */
     struct lys_node *parent;         /**< pointer to the parent node, NULL in case of a top level node */
-    struct lys_node *child;          /**< always NULL except the leaf/leaflist is target of a leafref, in that case
-                                          the pointer stores set of ::lys_node leafref objects with path referencing
-                                          the current ::lys_node_leaflist */
+    struct ly_set *backlinks;        /**< replacement for ::lys_node's child member, it is NULL except the leaf/leaflist
+                                          is target of a leafref. In that case the set stores ::lys_node leafref objects
+                                          with path referencing the current ::lys_node_leaf */
     struct lys_node *next;           /**< pointer to the next sibling node (NULL if there is no one) */
     struct lys_node *prev;           /**< pointer to the previous sibling node \note Note that this pointer is
                                           never NULL. If there is no sibling node, pointer points to the node
diff --git a/src/validation.c b/src/validation.c
index c876662..4138c7b 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -53,8 +53,6 @@
 {
     const struct lys_node *siter = NULL;
     struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
-    struct lys_type *type;
-    int found = 0;
 
     assert(node);
     assert(unres);
@@ -65,40 +63,20 @@
         return EXIT_FAILURE;
     }
 
-    /* check leafref/instance-identifier */
     if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-        if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
-            /* if leafref or instance-identifier, parse the value according to the
-             * target's type, because the target leaf does not need to be present */
-            if (leaf->value_type == LY_TYPE_LEAFREF || leaf->value_type == LY_TYPE_INST) {
-                memset(&leaf->value, 0, sizeof leaf->value);
-                if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, NULL,
-                                     (struct lyd_node *)node, leaf, 1, 0, 0)) {
-                    return EXIT_FAILURE;
-                }
+        /* if union with leafref/intsid, leafref itself (invalid) or instance-identifier, store the node for later resolving */
+        if ((((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_UNION)
+                && ((struct lys_node_leaf *)leaf->schema)->type.info.uni.has_ptr_type) {
+            if (unres_data_add(unres, (struct lyd_node *)node, UNRES_UNION)) {
+                return EXIT_FAILURE;
             }
-        } else {
-            /* if union with leafref, leafref itself or instance-identifier, store the node for later resolving */
-            if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_UNION) {
-                /* get know if there is leafref in the union types */
-                type = NULL;
-                while ((type = lyp_get_next_union_type(&((struct lys_node_leaf *)leaf->schema)->type, type, &found))) {
-                    found = 0;
-                    if (type->base == LY_TYPE_LEAFREF) {
-                        if (unres_data_add(unres, (struct lyd_node *)node, UNRES_UNION)) {
-                            return EXIT_FAILURE;
-                        }
-                        break;
-                    }
-                }
-            } else if (leaf->value_type == LY_TYPE_LEAFREF && !leaf->value.leafref) {
-                if (unres_data_add(unres, (struct lyd_node *)node, UNRES_LEAFREF)) {
-                    return EXIT_FAILURE;
-                }
-            } else if (leaf->value_type == LY_TYPE_INST) {
-                if (unres_data_add(unres, (struct lyd_node *)node, UNRES_INSTID)) {
-                    return EXIT_FAILURE;
-                }
+        } else if ((((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_LEAFREF) && (leaf->validity & LYD_VAL_LEAFREF)) {
+            if (unres_data_add(unres, (struct lyd_node *)node, UNRES_LEAFREF)) {
+                return EXIT_FAILURE;
+            }
+        } else if (((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_INST) {
+            if (unres_data_add(unres, (struct lyd_node *)node, UNRES_INSTID)) {
+                return EXIT_FAILURE;
             }
         }
     }
@@ -385,6 +363,42 @@
             }
         }
 
+        if (options & LYD_OPT_OBSOLETE) {
+            /* status - of the node's schema node itself and all its parents that
+             * cannot have their own instance (like a choice statement) */
+            siter = node->schema;
+            do {
+                if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
+                    LOGVAL(LYE_OBSDATA, LY_VLOG_LYD, node, schema->name);
+                    return EXIT_FAILURE;
+                }
+                siter = lys_parent(siter);
+            } while (siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA)));
+
+            /* status of the identity value */
+            if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+                if (options & LYD_OPT_OBSOLETE) {
+                    /* check that we are not instantiating obsolete type */
+                    tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
+                    while (tpdf) {
+                        if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
+                            LOGVAL(LYE_OBSTYPE, LY_VLOG_LYD, node, schema->name, tpdf->name);
+                            return EXIT_FAILURE;
+                        }
+                        tpdf = tpdf->type.der;
+                    }
+                }
+                if (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT) {
+                    ident = ((struct lyd_node_leaf_list *)node)->value.ident;
+                    if (lyp_check_status(schema->flags, schema->module, schema->name,
+                                    ident->flags, ident->module, ident->name, NULL)) {
+                        LOGPATH(LY_VLOG_LYD, node);
+                        return EXIT_FAILURE;
+                    }
+                }
+            }
+        }
+
         /* remove the flag */
         node->validity &= ~LYD_VAL_MAND;
     }
@@ -409,39 +423,7 @@
     }
 
     if (node->validity) {
-        /* status - of the node's schema node itself and all its parents that
-         * cannot have their own instance (like a choice statement) */
-        siter = node->schema;
-        do {
-            if (((siter->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) && (options & LYD_OPT_OBSOLETE)) {
-                LOGVAL(LYE_OBSDATA, LY_VLOG_LYD, node, schema->name);
-                return EXIT_FAILURE;
-            }
-            siter = lys_parent(siter);
-        } while (siter && !(siter->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA)));
 
-        /* status of the identity value */
-        if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-            if (options & LYD_OPT_OBSOLETE) {
-                /* check that we are not instantiating obsolete type */
-                tpdf = ((struct lys_node_leaf *)node->schema)->type.der;
-                while (tpdf) {
-                    if ((tpdf->flags & LYS_STATUS_MASK) == LYS_STATUS_OBSLT) {
-                        LOGVAL(LYE_OBSTYPE, LY_VLOG_LYD, node, schema->name, tpdf->name);
-                        return EXIT_FAILURE;
-                    }
-                    tpdf = tpdf->type.der;
-                }
-            }
-            if (((struct lyd_node_leaf_list *)node)->value_type == LY_TYPE_IDENT) {
-                ident = ((struct lyd_node_leaf_list *)node)->value.ident;
-                if (lyp_check_status(schema->flags, schema->module, schema->name,
-                                 ident->flags, ident->module, ident->name, NULL)) {
-                    LOGPATH(LY_VLOG_LYD, node);
-                    return EXIT_FAILURE;
-                }
-            }
-        }
     }
 
     if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
diff --git a/src/xpath.c b/src/xpath.c
index bc0ef2c..0dcce3b 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -43,8 +43,8 @@
 static const  struct lyd_node *moveto_get_root(const struct lyd_node *cur_node, int options,
                                                enum lyxp_node_type *root_type);
 static int reparse_expr(struct lyxp_expr *exp, uint16_t *exp_idx);
-static int eval_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                     int options);
+static int eval_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                     struct lyxp_set *set, int options);
 
 void
 lyxp_exp_free(struct lyxp_expr *exp)
@@ -345,12 +345,11 @@
  * @param[in,out] size Allocated bytes in \p str.
  */
 static void
-cast_string_recursive(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
-                      uint16_t *used, uint16_t *size)
+cast_string_recursive(struct lyd_node *node, struct lys_module *local_mod, int fake_cont, enum lyxp_node_type root_type,
+                      uint16_t indent, char **str, uint16_t *used, uint16_t *size)
 {
     char *buf, *line, *ptr;
     const char *value_str;
-    const struct lys_type *type;
     struct lyd_node *child;
     struct lyd_node_anydata *any;
 
@@ -376,7 +375,7 @@
         ++(*used);
 
         LY_TREE_FOR(node->child, child) {
-            cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
+            cast_string_recursive(child, local_mod, 0, root_type, indent + 1, str, used, size);
         }
 
         break;
@@ -389,11 +388,10 @@
         }
 
         /* make value canonical */
-        type = lyd_leaf_type((struct lyd_node_leaf_list *)node, 1);
-        if (type->base == LY_TYPE_IDENT) {
-            if (!strncmp(value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
-                    && (value_str[strlen(lyd_node_module(node)->name)] == ':')) {
-                value_str += strlen(lyd_node_module(node)->name) + 1;
+        if (((struct lyd_node_leaf_list *)node)->value_type & LY_TYPE_IDENT) {
+            if (!strncmp(value_str, local_mod->name, strlen(local_mod->name))
+                    && (value_str[strlen(local_mod->name)] == ':')) {
+                value_str += strlen(local_mod->name) + 1;
             }
         }
 
@@ -485,7 +483,7 @@
  * @return Element cast to dynamically-allocated string.
  */
 static char *
-cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type)
+cast_string_elem(struct lyd_node *node, struct lys_module *local_mod, int fake_cont, enum lyxp_node_type root_type)
 {
     char *str;
     uint16_t used, size;
@@ -499,7 +497,7 @@
     used = 1;
     size = LYXP_STRING_CAST_SIZE_START;
 
-    cast_string_recursive(node, fake_cont, root_type, 0, &str, &used, &size);
+    cast_string_recursive(node, local_mod, fake_cont, root_type, 0, &str, &used, &size);
 
     if (size > used) {
         str = ly_realloc(str, used * sizeof(char));
@@ -522,7 +520,7 @@
  * @return Cast string in the dictionary.
  */
 static char *
-cast_node_set_to_string(struct lyxp_set *set, struct lyd_node *cur_node, int options)
+cast_node_set_to_string(struct lyxp_set *set, struct lyd_node *cur_node, struct lys_module *local_mod, int options)
 {
     enum lyxp_node_type root_type;
 
@@ -536,10 +534,10 @@
     switch (set->val.nodes[0].type) {
     case LYXP_NODE_ROOT:
     case LYXP_NODE_ROOT_CONFIG:
-        return cast_string_elem(set->val.nodes[0].node, 1, root_type);
+        return cast_string_elem(set->val.nodes[0].node, local_mod, 1, root_type);
     case LYXP_NODE_ELEM:
     case LYXP_NODE_TEXT:
-        return cast_string_elem(set->val.nodes[0].node, 0, root_type);
+        return cast_string_elem(set->val.nodes[0].node, local_mod, 0, root_type);
     case LYXP_NODE_ATTR:
         return strdup(set->val.attrs[0].attr->value);
     }
@@ -1385,7 +1383,7 @@
         return 0;
     } else if (trg->type == LYXP_SET_EMPTY) {
         set_fill_set(trg, src);
-        lyxp_set_cast(src, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(src, LYXP_SET_EMPTY, cur_node, NULL, options);
         return 0;
     }
 
@@ -1471,7 +1469,7 @@
     print_set_debug(trg);
 #endif
 
-    lyxp_set_cast(src, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(src, LYXP_SET_EMPTY, cur_node, NULL, options);
     return 0;
 }
 
@@ -2608,8 +2606,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-                 int options)
+xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+                 struct lyxp_set *set, int options)
 {
     struct lyd_node_leaf_list *leaf;
     int i, bits_count;
@@ -2618,7 +2616,7 @@
         LOGVAL(LYE_XPATH_INARGTYPE, LY_VLOG_NONE, NULL, 1, print_set_type(args[0]), "bit-is-set(node-set, string)");
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -2653,10 +2651,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-              int options)
+xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+              struct lyxp_set *set, int options)
 {
-    lyxp_set_cast(args[0], LYXP_SET_BOOLEAN, cur_node, options);
+    lyxp_set_cast(args[0], LYXP_SET_BOOLEAN, cur_node, local_mod, options);
     set_fill_set(set, args[0]);
 
     return EXIT_SUCCESS;
@@ -2675,10 +2673,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-              int options)
+xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+              struct lyxp_set *set, int options)
 {
-    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, local_mod, options)) {
         return -1;
     }
     if ((long long)args[0]->val.num != args[0]->val.num) {
@@ -2703,15 +2701,15 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-             int options)
+xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+             struct lyxp_set *set, int options)
 {
     uint16_t i;
     char *str = NULL;
     size_t used = 1;
 
     for (i = 0; i < arg_count; ++i) {
-        if (lyxp_set_cast(args[i], LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(args[i], LYXP_SET_STRING, cur_node, local_mod, options)) {
             free(str);
             return -1;
         }
@@ -2726,7 +2724,7 @@
     }
 
     /* free, kind of */
-    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     set->type = LYXP_SET_STRING;
     set->val.str = str;
 
@@ -2747,13 +2745,13 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-               int options)
+xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+               struct lyxp_set *set, int options)
 {
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -2779,8 +2777,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node), struct lyxp_set *set,
-            int UNUSED(options))
+xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
+            struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
     if (args[0]->type == LYXP_SET_EMPTY) {
         set_fill_number(set, 0);
@@ -2809,7 +2807,7 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node,
+xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
               struct lyxp_set *set, int options)
 {
     if (arg_count || args) {
@@ -2822,7 +2820,7 @@
 
         set_snode_insert_node(set, (struct lys_node *)cur_node, LYXP_NODE_ELEM);
     } else {
-        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
 
         /* position is filled later */
         set_insert_node(set, cur_node, 0, LYXP_NODE_ELEM, 0);
@@ -2844,8 +2842,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-            int options)
+xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+            struct lyxp_set *set, int options)
 {
     struct lyd_node_leaf_list *leaf;
     struct lys_node_leaf *sleaf;
@@ -2867,15 +2865,16 @@
         }
         set_snode_insert_node(set, (struct lys_node *)cur_node, LYXP_NODE_ELEM);
     } else {
-        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         if (args[0]->type != LYXP_SET_EMPTY) {
             leaf = (struct lyd_node_leaf_list *)args[0]->val.nodes[0].node;
             sleaf = (struct lys_node_leaf *)leaf->schema;
             if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))
                     && ((sleaf->type.base == LY_TYPE_LEAFREF) || (sleaf->type.base == LY_TYPE_INST))) {
-                if (leaf->value_type & LY_TYPE_LEAFREF_UNRES) {
+                if (leaf->value_type & (LY_TYPE_LEAFREF_UNRES | LY_TYPE_INST_UNRES)) {
                     /* this is bad */
-                    LOGINT;
+                    LOGVAL(LYE_SPEC, LY_VLOG_LYD, args[0]->val.nodes[0].node,
+                           "Trying to dereference an unresolved leafref or instance-identifier.");
                     return -1;
                 }
                 /* works for both leafref and instid */
@@ -2931,8 +2930,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-                   int options)
+xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+                   struct lyxp_set *set, int options)
 {
     uint16_t i, j;
     struct lyd_node_leaf_list *leaf;
@@ -2942,7 +2941,7 @@
         LOGVAL(LYE_XPATH_INARGTYPE, LY_VLOG_NONE, NULL, 1, print_set_type(args[0]), "derived-from(node-set, string)");
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -2984,7 +2983,7 @@
  */
 static int
 xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node,
-                           struct lyxp_set *set, int options)
+                           struct lys_module *local_mod, struct lyxp_set *set, int options)
 {
     uint16_t i, j;
     struct lyd_node_leaf_list *leaf;
@@ -2994,7 +2993,7 @@
         LOGVAL(LYE_XPATH_INARGTYPE, LY_VLOG_NONE, NULL, 1, print_set_type(args[0]), "derived-from-or-self(node-set, string)");
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3040,7 +3039,7 @@
  */
 static int
 xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-                 struct lyxp_set *set, int UNUSED(options))
+                 struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
     struct lyd_node_leaf_list *leaf;
 
@@ -3075,7 +3074,7 @@
  */
 static int
 xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-            struct lyxp_set *set, int UNUSED(options))
+            struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
     set_fill_boolean(set, 0);
     return EXIT_SUCCESS;
@@ -3094,10 +3093,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-            int options)
+xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+            struct lyxp_set *set, int options)
 {
-    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, local_mod, options)) {
         return -1;
     }
     if (isfinite(args[0]->val.num)) {
@@ -3120,14 +3119,14 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-           int options)
+xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+           struct lyxp_set *set, int options)
 {
     const struct lyd_node *node, *root;
     struct lyd_attr *attr = NULL;
     int i;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3204,7 +3203,7 @@
  */
 static int
 xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-           struct lyxp_set *set, int UNUSED(options))
+           struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
 
     if (set->type == LYXP_SET_EMPTY) {
@@ -3233,8 +3232,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                 int options)
+xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *UNUSED(local_mod),
+                 struct lyxp_set *set, int options)
 {
     struct lyxp_set_nodes *item;
 
@@ -3313,10 +3312,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                 int options)
+xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+           struct lyxp_set *set, int options)
 {
-    return xpath_local_name(args, arg_count, cur_node, set, options);
+    return xpath_local_name(args, arg_count, cur_node, local_mod, set, options);
 }
 
 /**
@@ -3332,8 +3331,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                    int options)
+xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *UNUSED(local_mod),
+                    struct lyxp_set *set, int options)
 {
     struct lyxp_set_nodes *item;
     struct lys_module *module;
@@ -3418,11 +3417,11 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-           int options)
+xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+           struct lyxp_set *set, int options)
 {
     if (set->type != LYXP_SET_NODE_SET) {
-        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     }
     return EXIT_SUCCESS;
 }
@@ -3441,8 +3440,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                      int options)
+xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+                      struct lyxp_set *set, int options)
 {
     uint16_t i, new_used;
     char *new;
@@ -3451,7 +3450,7 @@
     if (arg_count) {
         set_fill_set(set, args[0]);
     }
-    if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3527,10 +3526,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-          int options)
+xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+          struct lyxp_set *set, int options)
 {
-    lyxp_set_cast(args[0], LYXP_SET_BOOLEAN, cur_node, options);
+    lyxp_set_cast(args[0], LYXP_SET_BOOLEAN, cur_node, local_mod, options);
     if (args[0]->val.bool) {
         set_fill_boolean(set, 0);
     } else {
@@ -3553,16 +3552,16 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-             int options)
+xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+             struct lyxp_set *set, int options)
 {
     if (arg_count) {
-        if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, options)) {
+        if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, local_mod, options)) {
             return -1;
         }
         set_fill_set(set, args[0]);
     } else {
-        if (lyxp_set_cast(set, LYXP_SET_NUMBER, cur_node, options)) {
+        if (lyxp_set_cast(set, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
             return -1;
         }
     }
@@ -3584,7 +3583,7 @@
  */
 static int
 xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-               struct lyxp_set *set, int options)
+               struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int options)
 {
     if (set->type == LYXP_SET_EMPTY) {
         set_fill_number(set, 0);
@@ -3616,15 +3615,15 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-               int options)
+xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+               struct lyxp_set *set, int options)
 {
     pcre *precomp;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3655,10 +3654,10 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-            int options)
+xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+            struct lyxp_set *set, int options)
 {
-    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_NUMBER, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3667,7 +3666,7 @@
         set_fill_number(set, -0.0f);
     } else {
         args[0]->val.num += 0.5;
-        if (xpath_floor(args, 1, cur_node, args[0], options)) {
+        if (xpath_floor(args, 1, cur_node, local_mod, args[0], options)) {
             return -1;
         }
         set_fill_number(set, args[0]->val.num);
@@ -3690,13 +3689,13 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-                  int options)
+xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+                  struct lyxp_set *set, int options)
 {
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3722,16 +3721,16 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-             int options)
+xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+             struct lyxp_set *set, int options)
 {
     if (arg_count) {
-        if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
         set_fill_set(set, args[0]);
     } else {
-        if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
     }
@@ -3752,16 +3751,16 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                    int options)
+xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+                    struct lyxp_set *set, int options)
 {
     if (arg_count) {
-        if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
         set_fill_number(set, strlen(args[0]->val.str));
     } else {
-        if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(set, LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
         set_fill_number(set, strlen(set->val.str));
@@ -3786,18 +3785,18 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lyxp_set *set,
-                int options)
+xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyd_node *cur_node, struct lys_module *local_mod,
+                struct lyxp_set *set, int options)
 {
     int start, len;
     uint16_t str_start, str_len, pos;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
     /* start */
-    if (xpath_round(&args[1], 1, cur_node, args[1], options)) {
+    if (xpath_round(&args[1], 1, cur_node, local_mod, args[1], options)) {
         return -1;
     }
     if (isfinite(args[1]->val.num)) {
@@ -3810,7 +3809,7 @@
 
     /* len */
     if (arg_count == 3) {
-        if (xpath_round(&args[2], 1, cur_node, args[2], options)) {
+        if (xpath_round(&args[2], 1, cur_node, local_mod, args[2], options)) {
             return -1;
         }
         if (isfinite(args[2]->val.num)) {
@@ -3856,14 +3855,14 @@
  */
 static int
 xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node,
-                      struct lyxp_set *set, int options)
+                      struct lys_module *local_mod, struct lyxp_set *set, int options)
 {
     char *ptr;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3892,14 +3891,14 @@
  */
 static int
 xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node,
-                       struct lyxp_set *set, int options)
+                       struct lys_module *local_mod, struct lyxp_set *set, int options)
 {
     char *ptr;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -3926,8 +3925,8 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-          int options)
+xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lys_module *local_mod,
+          struct lyxp_set *set, int options)
 {
     long double num;
     char *str;
@@ -3957,7 +3956,7 @@
     for (i = 0; i < args[0]->used; ++i) {
         set_item.val.nodes[0] = args[0]->val.nodes[i];
 
-        str = cast_node_set_to_string(&set_item, cur_node, options);
+        str = cast_node_set_to_string(&set_item, cur_node, local_mod, options);
         if (!str) {
             return -1;
         }
@@ -3985,7 +3984,7 @@
  */
 static int
 xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-           struct lyxp_set *set, int UNUSED(options))
+           struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
     uint32_t i;
 
@@ -4038,20 +4037,20 @@
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node, struct lyxp_set *set,
-                int options)
+xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyd_node *cur_node,
+                struct lys_module *local_mod, struct lyxp_set *set, int options)
 {
     uint16_t i, j, new_used;
     char *new;
     int found, have_removed;
 
-    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[0], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[1], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(args[2], LYXP_SET_STRING, cur_node, options)) {
+    if (lyxp_set_cast(args[2], LYXP_SET_STRING, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -4098,7 +4097,7 @@
     }
     new[new_used] = '\0';
 
-    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     set->type = LYXP_SET_STRING;
     set->val.str = new;
 
@@ -4119,7 +4118,7 @@
  */
 static int
 xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyd_node *UNUSED(cur_node),
-           struct lyxp_set *set, int UNUSED(options))
+           struct lys_module *UNUSED(local_mod), struct lyxp_set *set, int UNUSED(options))
 {
     set_fill_boolean(set, 1);
     return EXIT_SUCCESS;
@@ -4272,7 +4271,7 @@
 
     root = moveto_get_root(cur_node, options, &root_type);
 
-    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, NULL, options);
     if (root) {
         set_insert_node(set, root, 0, root_type, 0);
     }
@@ -5480,7 +5479,7 @@
  */
 static int
 moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, struct lyd_node *cur_node,
-               int options)
+               struct lys_module *local_mod, int options)
 {
     /*
      * NODE SET + NODE SET = STRING + STRING  /1 STRING, 2 STRING
@@ -5564,7 +5563,7 @@
             set_fill_boolean(set1, 0);
         }
 
-        lyxp_set_cast(set2, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return EXIT_SUCCESS;
     }
 
@@ -5572,30 +5571,30 @@
     if (((set1->type == LYXP_SET_NODE_SET) || (set1->type == LYXP_SET_EMPTY) || (set1->type == LYXP_SET_STRING))
             && ((set2->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_STRING))
             && ((set1->type != LYXP_SET_STRING) || (set2->type != LYXP_SET_STRING))) {
-        if (lyxp_set_cast(set1, LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(set1, LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
-        if (lyxp_set_cast(set2, LYXP_SET_STRING, cur_node, options)) {
+        if (lyxp_set_cast(set2, LYXP_SET_STRING, cur_node, local_mod, options)) {
             return -1;
         }
 
     } else if ((((set1->type == LYXP_SET_NODE_SET) || (set1->type == LYXP_SET_EMPTY) || (set1->type == LYXP_SET_BOOLEAN))
             && ((set2->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_BOOLEAN)))
             || (((op[0] == '=') || (op[0] == '!')) && ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)))) {
-        lyxp_set_cast(set1, LYXP_SET_BOOLEAN, cur_node, options);
-        lyxp_set_cast(set2, LYXP_SET_BOOLEAN, cur_node, options);
+        lyxp_set_cast(set1, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
+        lyxp_set_cast(set2, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
 
     } else {
-        if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, options)) {
+        if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
             return -1;
         }
-        if (lyxp_set_cast(set2, LYXP_SET_NUMBER, cur_node, options)) {
+        if (lyxp_set_cast(set2, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
             return -1;
         }
     }
 
     /* now we can evaluate */
-    return moveto_op_comp(set1, set2, op, cur_node, options);
+    return moveto_op_comp(set1, set2, op, cur_node, local_mod, options);
 }
 
 /**
@@ -5611,11 +5610,11 @@
  */
 static int
 moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, struct lyd_node *cur_node,
-               int options)
+               struct lys_module *local_mod, int options)
 {
     /* unary '-' */
     if (!set2 && (op[0] == '-')) {
-        if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, options)) {
+        if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
             return -1;
         }
         set1->val.num *= -1;
@@ -5625,10 +5624,10 @@
 
     assert(set1 && set2);
 
-    if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, options)) {
+    if (lyxp_set_cast(set1, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
         return -1;
     }
-    if (lyxp_set_cast(set2, LYXP_SET_NUMBER, cur_node, options)) {
+    if (lyxp_set_cast(set2, LYXP_SET_NUMBER, cur_node, local_mod, options)) {
         return -1;
     }
 
@@ -5712,8 +5711,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, int attr_axis, int all_desc,
-               struct lyxp_set *set, int options)
+eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+               int attr_axis, int all_desc, struct lyxp_set *set, int options)
 {
     int i, rc = 0;
 
@@ -5782,12 +5781,12 @@
                 set = NULL;
             } else {
                 if (!strncmp(&exp->expr[exp->expr_pos[*exp_idx]], "node", 4)) {
-                    if (xpath_node(NULL, 0, cur_node, set, options)) {
+                    if (xpath_node(NULL, 0, cur_node, local_mod, set, options)) {
                         return -1;
                     }
                 } else {
                     assert(!strncmp(&exp->expr[exp->expr_pos[*exp_idx]], "text", 4));
-                    if (xpath_text(NULL, 0, cur_node, set, options)) {
+                    if (xpath_text(NULL, 0, cur_node, local_mod, set, options)) {
                         return -1;
                     }
                 }
@@ -5830,8 +5829,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-               int options)
+eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+               struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t i, j, orig_exp, brack2_exp;
@@ -5845,7 +5844,7 @@
     ++(*exp_idx);
 
     if (!set) {
-        ret = eval_expr(exp, exp_idx, cur_node, NULL, options);
+        ret = eval_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
         if (ret) {
             return ret;
         }
@@ -5903,13 +5902,13 @@
                 }
             }
 
-            ret = eval_expr(exp, exp_idx, cur_node, &set2, options);
+            ret = eval_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
             if (ret) {
                 for (j = 0; j < brack2_exp - orig_exp; ++j) {
                     free(pred_repeat[j]);
                 }
                 free(pred_repeat);
-                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
                 return ret;
             }
 
@@ -5921,7 +5920,7 @@
                     set2.val.num = 0;
                 }
             }
-            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, options);
+            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
 
             /* predicate satisfied or not? */
             if (set2.val.bool) {
@@ -5987,7 +5986,7 @@
                 }
             }
 
-            ret = eval_expr(exp, exp_idx, cur_node, set, options);
+            ret = eval_expr(exp, exp_idx, cur_node, local_mod, set, options);
             if (ret) {
                 for (j = 0; j < brack2_exp - orig_exp; ++j) {
                     free(pred_repeat[j]);
@@ -6017,17 +6016,17 @@
         set2.type = LYXP_SET_EMPTY;
         set_fill_set(&set2, set);
 
-        ret = eval_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
-        lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, options);
+        lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
         if (!set2.val.bool) {
-            lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         }
-        lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
     }
 
     /* ']' */
@@ -6054,8 +6053,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, int all_desc,
-                            struct lyxp_set *set, int options)
+eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                            int all_desc, struct lyxp_set *set, int options)
 {
     int attr_axis, ret;
 
@@ -6115,12 +6114,12 @@
             /* fall through */
         case LYXP_TOKEN_NAMETEST:
         case LYXP_TOKEN_NODETYPE:
-            ret = eval_node_test(exp, exp_idx, cur_node, attr_axis, all_desc, set, options);
+            ret = eval_node_test(exp, exp_idx, cur_node, local_mod, attr_axis, all_desc, set, options);
             if (ret) {
                 return ret;
             }
             while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
-                ret = eval_predicate(exp, exp_idx, cur_node, set, options);
+                ret = eval_predicate(exp, exp_idx, cur_node, local_mod, set, options);
                 if (ret) {
                     return ret;
                 }
@@ -6149,7 +6148,7 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node,
+eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
                             struct lyxp_set *set, int options)
 {
     int all_desc, ret;
@@ -6180,7 +6179,7 @@
         case LYXP_TOKEN_AT:
         case LYXP_TOKEN_NAMETEST:
         case LYXP_TOKEN_NODETYPE:
-            ret = eval_relative_location_path(exp, exp_idx, cur_node, all_desc, set, options);
+            ret = eval_relative_location_path(exp, exp_idx, cur_node, local_mod, all_desc, set, options);
             if (ret) {
                 return ret;
             }
@@ -6196,7 +6195,7 @@
                print_token(exp->tokens[*exp_idx]), exp->expr_pos[*exp_idx]);
         ++(*exp_idx);
 
-        ret =  eval_relative_location_path(exp, exp_idx, cur_node, all_desc, set, options);
+        ret =  eval_relative_location_path(exp, exp_idx, cur_node, local_mod, all_desc, set, options);
         if (ret) {
             return ret;
         }
@@ -6219,11 +6218,11 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                   int options)
+eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                   struct lyxp_set *set, int options)
 {
     int rc = EXIT_FAILURE;
-    int (*xpath_func)(struct lyxp_set **, uint16_t, struct lyd_node *, struct lyxp_set *, int) = NULL;
+    int (*xpath_func)(struct lyxp_set **, uint16_t, struct lyd_node *, struct lys_module *, struct lyxp_set *, int) = NULL;
     uint16_t arg_count = 0, i;
     struct lyxp_set **args = NULL, **args_aux;
 
@@ -6371,11 +6370,11 @@
                 goto cleanup;
             }
 
-            if ((rc = eval_expr(exp, exp_idx, cur_node, args[0], options))) {
+            if ((rc = eval_expr(exp, exp_idx, cur_node, local_mod, args[0], options))) {
                 goto cleanup;
             }
         } else {
-            if ((rc = eval_expr(exp, exp_idx, cur_node, NULL, options))) {
+            if ((rc = eval_expr(exp, exp_idx, cur_node, local_mod, NULL, options))) {
                 goto cleanup;
             }
         }
@@ -6399,11 +6398,11 @@
                 goto cleanup;
             }
 
-            if ((rc = eval_expr(exp, exp_idx, cur_node, args[arg_count - 1], options))) {
+            if ((rc = eval_expr(exp, exp_idx, cur_node, local_mod, args[arg_count - 1], options))) {
                 goto cleanup;
             }
         } else {
-            if ((rc = eval_expr(exp, exp_idx, cur_node, NULL, options))) {
+            if ((rc = eval_expr(exp, exp_idx, cur_node, local_mod, NULL, options))) {
                 goto cleanup;
             }
         }
@@ -6416,7 +6415,7 @@
 
     if (set) {
         /* evaluate function */
-        rc = xpath_func(args, arg_count, cur_node, set, options);
+        rc = xpath_func(args, arg_count, cur_node, local_mod, set, options);
     } else {
         rc = EXIT_SUCCESS;
     }
@@ -6487,8 +6486,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-               int options)
+eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+               struct lyxp_set *set, int options)
 {
     int all_desc, ret;
 
@@ -6502,7 +6501,7 @@
         ++(*exp_idx);
 
         /* Expr */
-        ret = eval_expr(exp, exp_idx, cur_node, set, options);
+        ret = eval_expr(exp, exp_idx, cur_node, local_mod, set, options);
         if (ret) {
             return ret;
         }
@@ -6520,7 +6519,7 @@
     case LYXP_TOKEN_NAMETEST:
     case LYXP_TOKEN_NODETYPE:
         /* RelativeLocationPath */
-        ret = eval_relative_location_path(exp, exp_idx, cur_node, 0, set, options);
+        ret = eval_relative_location_path(exp, exp_idx, cur_node, local_mod, 0, set, options);
         if (ret) {
             return ret;
         }
@@ -6532,9 +6531,9 @@
             if (set) {
                 /* the only function returning node-set - thus relevant */
                 if ((exp->tok_len[*exp_idx] == 7) && !strncmp(&exp->expr[exp->expr_pos[*exp_idx]], "current", 7)) {
-                    xpath_current(NULL, 0, cur_node, set, options);
+                    xpath_current(NULL, 0, cur_node, local_mod, set, options);
                 } else if ((exp->tok_len[*exp_idx] == 5) && !strncmp(&exp->expr[exp->expr_pos[*exp_idx]], "deref", 5)) {
-                    ret = eval_function_call(exp, exp_idx, cur_node, set, options);
+                    ret = eval_function_call(exp, exp_idx, cur_node, local_mod, set, options);
                     if (ret) {
                         return ret;
                     }
@@ -6543,9 +6542,9 @@
                     set_snode_clear_ctx(set);
                 }
             }
-            ret = eval_function_call(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_function_call(exp, exp_idx, cur_node, local_mod, NULL, options);
         } else {
-            ret = eval_function_call(exp, exp_idx, cur_node, set, options);
+            ret = eval_function_call(exp, exp_idx, cur_node, local_mod, set, options);
         }
         if (ret) {
             return ret;
@@ -6555,7 +6554,7 @@
 
     case LYXP_TOKEN_OPERATOR_PATH:
         /* AbsoluteLocationPath */
-        ret = eval_absolute_location_path(exp, exp_idx, cur_node, set, options);
+        ret = eval_absolute_location_path(exp, exp_idx, cur_node, local_mod, set, options);
         if (ret) {
             return ret;
         }
@@ -6601,7 +6600,7 @@
 predicate:
     /* Predicate* */
     while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
-        ret = eval_predicate(exp, exp_idx, cur_node, set, options);
+        ret = eval_predicate(exp, exp_idx, cur_node, local_mod, set, options);
         if (ret) {
             return ret;
         }
@@ -6622,7 +6621,7 @@
                print_token(exp->tokens[*exp_idx]), exp->expr_pos[*exp_idx]);
         ++(*exp_idx);
 
-        ret = eval_relative_location_path(exp, exp_idx, cur_node, all_desc, set, options);
+        ret = eval_relative_location_path(exp, exp_idx, cur_node, local_mod, all_desc, set, options);
         if (ret) {
             return ret;
         }
@@ -6646,8 +6645,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                int options)
+eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                struct lyxp_set *set, int options)
 {
     int unary_minus, ret;
     uint16_t op_exp;
@@ -6681,9 +6680,9 @@
     }
 
     /* PathExpr */
-    ret = eval_path_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_path_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -6702,7 +6701,7 @@
         }
 
         if (!set) {
-            ret = eval_path_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_path_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -6710,10 +6709,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_path_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_path_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -6721,17 +6720,17 @@
         if (options & LYXP_SNODE_ALL) {
             set_snode_merge(set, &set2);
         } else if (moveto_union(set, &set2, cur_node, options)) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return -1;
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     /* now we have all the unions in set and no other memory allocated */
 
     if (set && (unary_minus > -1) && !(options & LYXP_SNODE_ALL)) {
-        if (moveto_op_math(set, NULL, &exp->expr[exp->expr_pos[unary_minus]], cur_node, options)) {
+        if (moveto_op_math(set, NULL, &exp->expr[exp->expr_pos[unary_minus]], cur_node, local_mod, options)) {
             return -1;
         }
     }
@@ -6756,8 +6755,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                         int options)
+eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                         struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t this_op, op_exp;
@@ -6777,9 +6776,9 @@
     }
 
     /* UnaryExpr */
-    ret = eval_unary_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_unary_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -6801,7 +6800,7 @@
         }
 
         if (!set) {
-            ret = eval_unary_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_unary_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -6809,10 +6808,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_unary_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_unary_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -6821,15 +6820,15 @@
             set_snode_merge(set, &set2);
             set_snode_clear_ctx(set);
         } else {
-            if (moveto_op_math(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, options)) {
-                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            if (moveto_op_math(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, local_mod, options)) {
+                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
                 return -1;
             }
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
@@ -6849,8 +6848,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                   int options)
+eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                   struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t this_op, op_exp;
@@ -6870,9 +6869,9 @@
     }
 
     /* MultiplicativeExpr */
-    ret = eval_multiplicative_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_multiplicative_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -6894,7 +6893,7 @@
         }
 
         if (!set) {
-            ret = eval_multiplicative_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_multiplicative_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -6902,10 +6901,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_multiplicative_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_multiplicative_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -6914,15 +6913,15 @@
             set_snode_merge(set, &set2);
             set_snode_clear_ctx(set);
         } else {
-            if (moveto_op_math(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, options)) {
-                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            if (moveto_op_math(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, local_mod, options)) {
+                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
                 return -1;
             }
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
@@ -6944,8 +6943,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                     int options)
+eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                     struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t this_op, op_exp;
@@ -6965,9 +6964,9 @@
     }
 
     /* AdditiveExpr */
-    ret = eval_additive_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_additive_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -6989,7 +6988,7 @@
         }
 
         if (!set) {
-            ret = eval_additive_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_additive_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -6997,10 +6996,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_additive_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_additive_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -7009,15 +7008,15 @@
             set_snode_merge(set, &set2);
             set_snode_clear_ctx(set);
         } else {
-            if (moveto_op_comp(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, options)) {
-                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            if (moveto_op_comp(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, local_mod, options)) {
+                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
                 return -1;
             }
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
@@ -7036,8 +7035,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-                   int options)
+eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+                   struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t this_op, op_exp;
@@ -7057,9 +7056,9 @@
     }
 
     /* RelationalExpr */
-    ret = eval_relational_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_relational_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -7081,7 +7080,7 @@
         }
 
         if (!set) {
-            ret = eval_relational_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_relational_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -7089,10 +7088,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_relational_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_relational_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -7101,15 +7100,15 @@
             set_snode_merge(set, &set2);
             set_snode_clear_ctx(set);
         } else {
-            if (moveto_op_comp(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, options)) {
-                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            if (moveto_op_comp(set, &set2, &exp->expr[exp->expr_pos[this_op]], cur_node, local_mod, options)) {
+                lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+                lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
                 return -1;
             }
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
@@ -7127,8 +7126,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set,
-              int options)
+eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+              struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t op_exp;
@@ -7147,9 +7146,9 @@
     }
 
     /* EqualityExpr */
-    ret = eval_equality_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_equality_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -7158,7 +7157,7 @@
         if (set && (options & LYXP_SNODE_ALL)) {
             set_snode_clear_ctx(set);
         } else {
-            lyxp_set_cast(set, LYXP_SET_BOOLEAN, cur_node, options);
+            lyxp_set_cast(set, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
         }
     }
 
@@ -7178,7 +7177,7 @@
 
         /* lazy evaluation */
         if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
-            ret = eval_equality_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_equality_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -7186,10 +7185,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_equality_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_equality_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -7198,12 +7197,12 @@
             set_snode_clear_ctx(&set2);
             set_snode_merge(set, &set2);
         } else {
-            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, options);
+            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
             set_fill_set(set, &set2);
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
@@ -7221,7 +7220,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when, -1 on error.
  */
 static int
-eval_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lyxp_set *set, int options)
+eval_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyd_node *cur_node, struct lys_module *local_mod,
+          struct lyxp_set *set, int options)
 {
     int ret;
     uint16_t op_exp;
@@ -7240,9 +7240,9 @@
     }
 
     /* AndExpr */
-    ret = eval_and_expr(exp, exp_idx, cur_node, set, options);
+    ret = eval_and_expr(exp, exp_idx, cur_node, local_mod, set, options);
     if (ret) {
-        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+        lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
         return ret;
     }
 
@@ -7251,7 +7251,7 @@
         if (set && (options & LYXP_SNODE_ALL)) {
             set_snode_clear_ctx(set);
         } else {
-            lyxp_set_cast(set, LYXP_SET_BOOLEAN, cur_node, options);
+            lyxp_set_cast(set, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
         }
     }
 
@@ -7271,7 +7271,7 @@
 
         /* lazy evaluation */
         if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
-            ret = eval_and_expr(exp, exp_idx, cur_node, NULL, options);
+            ret = eval_and_expr(exp, exp_idx, cur_node, local_mod, NULL, options);
             if (ret) {
                 return ret;
             }
@@ -7279,10 +7279,10 @@
         }
 
         set_fill_set(&set2, &orig_set);
-        ret = eval_and_expr(exp, exp_idx, cur_node, &set2, options);
+        ret = eval_and_expr(exp, exp_idx, cur_node, local_mod, &set2, options);
         if (ret) {
-            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
-            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, options);
+            lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
+            lyxp_set_cast(&set2, LYXP_SET_EMPTY, cur_node, local_mod, options);
             return ret;
         }
 
@@ -7291,18 +7291,18 @@
             set_snode_clear_ctx(&set2);
             set_snode_merge(set, &set2);
         } else {
-            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, options);
+            lyxp_set_cast(&set2, LYXP_SET_BOOLEAN, cur_node, local_mod, options);
             set_fill_set(set, &set2);
         }
     }
 
-    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, options);
+    lyxp_set_cast(&orig_set, LYXP_SET_EMPTY, cur_node, local_mod, options);
     return EXIT_SUCCESS;
 }
 
 int
-lyxp_eval(const char *expr, const struct lyd_node *cur_node, enum lyxp_node_type cur_node_type, struct lyxp_set *set,
-          int options)
+lyxp_eval(const char *expr, const struct lyd_node *cur_node, enum lyxp_node_type cur_node_type,
+          const struct lys_module *local_mod, struct lyxp_set *set, int options)
 {
     struct lyxp_expr *exp;
     uint16_t exp_idx = 0;
@@ -7338,7 +7338,7 @@
         set_insert_node(set, (struct lyd_node *)cur_node, 0, cur_node_type, 0);
     }
 
-    rc = eval_expr(exp, &exp_idx, (struct lyd_node *)cur_node, set, options);
+    rc = eval_expr(exp, &exp_idx, (struct lyd_node *)cur_node, (struct lys_module *)local_mod, set, options);
     if ((rc == -1) && cur_node) {
         LOGPATH(LY_VLOG_LYD, cur_node);
     }
@@ -7445,7 +7445,8 @@
 #endif
 
 int
-lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node, int options)
+lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node,
+              const struct lys_module *local_mod, int options)
 {
     long double num;
     char *str;
@@ -7506,7 +7507,7 @@
             }
 #endif
 
-            str = cast_node_set_to_string(set, (struct lyd_node *)cur_node, options);
+            str = cast_node_set_to_string(set, (struct lyd_node *)cur_node, (struct lys_module *)local_mod, options);
             if (!str) {
                 return -1;
             }
@@ -7656,7 +7657,7 @@
     set->type = LYXP_SET_SNODE_SET;
     set_snode_insert_node(set, cur_snode, cur_snode_type);
 
-    rc = eval_expr(exp, &exp_idx, (struct lyd_node *)cur_snode, set, options);
+    rc = eval_expr(exp, &exp_idx, (struct lyd_node *)cur_snode, lys_node_module(cur_snode), set, options);
 
 finish:
     lyxp_exp_free(exp);
diff --git a/src/xpath.h b/src/xpath.h
index 99f7106..865c5f0 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -203,6 +203,7 @@
  * this case just pass the first top-level node into \p cur_node and use an enum value for this kind of root
  * (#LYXP_NODE_ROOT_CONFIG if \p cur_node has config true, otherwise #LYXP_NODE_ROOT). #LYXP_NODE_TEXT and #LYXP_NODE_ATTR can also be used,
  * but there are no use-cases in YANG.
+ * @param[in] local_mod Local module relative to the \p expr. Used only to determine the internal canonical value for identities.
  * @param[out] set Result set. Must be valid and in the same libyang context as \p cur_node.
  * To be safe, always either zero or cast the \p set to empty. After done using, either cast
  * the \p set to empty (if allocated statically) or free it (if allocated dynamically) to
@@ -214,7 +215,7 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when dependency, -1 on error.
  */
 int lyxp_eval(const char *expr, const struct lyd_node *cur_node, enum lyxp_node_type cur_node_type,
-              struct lyxp_set *set, int options);
+              const struct lys_module *local_mod, struct lyxp_set *set, int options);
 
 /**
  * @brief Get all the partial XPath nodes (atoms) that are required for \p expr to be evaluated.
@@ -264,11 +265,13 @@
  * @param[in] set Set to cast.
  * @param[in] target Target type to cast \p set into.
  * @param[in] cur_node Current (context) data node. Cannot be NULL.
+ * @param[in] local_mod Local expression module.
  * @param[in] options Whether to apply some evaluation restrictions.
  *
  * @return EXIT_SUCCESS on success, -1 on error.
  */
-int lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node, int options);
+int lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node,
+                  const struct lys_module *local_mod, int options);
 
 /**
  * @brief Free contents of an XPath \p set.