tree CHANGE invalid xpath is accepted with a warning
diff --git a/src/log.c b/src/log.c
index 59f2767..4a57c66 100644
--- a/src/log.c
+++ b/src/log.c
@@ -108,10 +108,7 @@
         }
     }
 
-    if (hide == 0xff && level == LY_LLERR && (LY_LLWRN <= ly_log_level)) {
-        /* change error to warning */
-        level = LY_LLWRN;
-    } else if (hide || (level > ly_log_level)) {
+    if (hide || (level > ly_log_level)) {
         /* do not print the message */
         goto clean;
     }
@@ -139,7 +136,7 @@
     va_list ap;
 
     va_start(ap, format);
-    log_vprintf(level, 0, format, NULL, ap);
+    log_vprintf(level, (*ly_vlog_hide_location()), format, NULL, ap);
     va_end(ap);
 }
 
diff --git a/src/resolve.c b/src/resolve.c
index a90725d..6427ff7 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -4173,12 +4173,12 @@
 }
 
 int
-lys_check_xpath(struct lys_node *node, int check_place)
+lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
 {
     struct lys_node *parent, *elem;
     struct lyxp_set set;
     uint32_t i;
-    int rc;
+    int ret;
 
     if (check_place) {
         parent = node;
@@ -4206,9 +4206,9 @@
         }
     }
 
-    rc = lyxp_node_atomize(node, &set);
-    if (rc) {
-        return rc;
+    ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
+    if (ret == -1) {
+        return -1;
     }
 
     for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
@@ -4234,7 +4234,7 @@
     }
 
     free(set.val.snodes);
-    return EXIT_SUCCESS;
+    return ret;
 }
 
 static int
@@ -6026,12 +6026,13 @@
  * @param[in] type Type of the unresolved item.
  * @param[in] str_snode String, a schema node, or NULL.
  * @param[in] unres Unres schema structure to use.
+ * @param[in] final_fail Whether we are just printing errors of the failed unres items.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
 resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
-                          struct unres_schema *unres)
+                          struct unres_schema *unres, int final_fail)
 {
     /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
     int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
@@ -6250,7 +6251,7 @@
         break;
     case UNRES_XPATH:
         node = (struct lys_node *)item;
-        rc = lys_check_xpath(node, 1);
+        rc = lys_check_xpath(node, 1, final_fail);
         break;
     default:
         LOGINT;
@@ -6378,7 +6379,7 @@
              * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
 
             ++unres_count;
-            rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+            rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
             if (!rc) {
                 unres->type[i] = UNRES_RESOLVED;
                 ++resolved;
@@ -6386,7 +6387,7 @@
             } else if (rc == -1) {
                 ly_vlog_hide(0);
                 /* print the error */
-                resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+                resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
                 return -1;
             } else {
                 /* forward reference, erase ly_errno */
@@ -6403,7 +6404,7 @@
             if (unres->type[i] > UNRES_IDENT) {
                 continue;
             }
-            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
         }
         return -1;
     }
@@ -6414,7 +6415,7 @@
             continue;
         }
 
-        rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+        rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
         if (rc == 0) {
             if (unres->type[i] == UNRES_LIST_UNIQ) {
                 /* free the allocated structure */
@@ -6425,7 +6426,7 @@
         } else if (rc == -1) {
             ly_vlog_hide(0);
             /* print the error */
-            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
             return -1;
         }
     }
@@ -6440,17 +6441,11 @@
             if (unres->type[i] == UNRES_RESOLVED) {
                 continue;
             }
+            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
             if (unres->type[i] == UNRES_XPATH) {
-                /* unresolvable XPaths are actually supposed to be warnings - they may be
-                 * unresolved due to the not implemented target module so it shouldn't avoid
-                 * parsing the module, but we still want to announce some issue here */
-                ly_vlog_hide(0xff);
-            }
-            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
-            if (unres->type[i] == UNRES_XPATH && *ly_vlog_hide_location() == 0xff) {
+                /* XPath referencing an unknown node is actually supposed to be just a warning */
                 unres->type[i] = UNRES_RESOLVED;
                 resolved++;
-                ly_vlog_hide(0);
             }
         }
         if (resolved < unres->count) {
@@ -6528,7 +6523,7 @@
         log_hidden = 0;
         ly_vlog_hide(1);
     }
-    rc = resolve_unres_schema_item(mod, item, type, snode, unres);
+    rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
     if (!log_hidden) {
         ly_vlog_hide(0);
     }
@@ -6543,7 +6538,7 @@
         } else if (rc == -1 && type == UNRES_IFFEAT) {
             /* free the allocated resources */
             free(*((char **)item));
-         }
+        }
         return rc;
     } else {
         /* erase info about validation errors */
diff --git a/src/tree_internal.h b/src/tree_internal.h
index c87f0fa..4045f6a 100644
--- a/src/tree_internal.h
+++ b/src/tree_internal.h
@@ -181,9 +181,10 @@
  *
  * @param[in] node Node to examine.
  * @param[in] check_place Check where the node is placed to get know if the check is supposed to be performed
+ * @param[in] warn_on_fwd_ref Whether to not print errors and only warn on forward references.
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
-int lys_check_xpath(struct lys_node *node, int check_place);
+int lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref);
 
 /**
  * @brief Get know if the node contains must or when with XPath expression
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 0ba99f1..33df466 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -3378,7 +3378,7 @@
             goto next_iter;
         }
 
-        if (lyxp_node_atomize(elem, &set)) {
+        if (lyxp_node_atomize(elem, &set, 0)) {
             ly_set_free(ret_set);
             free(set.val.snodes);
             return NULL;
diff --git a/src/xpath.c b/src/xpath.c
index e52fc45..4af4b21 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4574,13 +4574,6 @@
                 set->val.snodes[i].in_ctx = 1;
             }
         }
-    } else if (orig_used == (int)set->used && !moveto_mod) {
-        /* no new node inserted into set (all are invalid now) and we were searching
-         * in the same schema as the previous node, so this is definitely a bug in expression,
-         * avoid changing it to just a warning */
-        if (*ly_vlog_hide_location() == 0xff) {
-            ly_vlog_hide(0);
-        }
     }
 
     return EXIT_SUCCESS;
@@ -7659,17 +7652,19 @@
 }
 
 int
-lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set)
+lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set, int warn_on_fwd_ref)
 {
     struct lys_node *ctx_snode;
     enum lyxp_node_type ctx_snode_type;
     struct lyxp_set tmp_set;
     uint8_t must_size = 0;
     uint32_t i;
-    int opts;
+    int opts, ret = EXIT_SUCCESS;
     struct lys_when *when = NULL;
     struct lys_restr *must = NULL;
 
+    assert(!warn_on_fwd_ref || !*ly_vlog_hide_location());
+
     memset(&tmp_set, 0, sizeof tmp_set);
     memset(set, 0, sizeof *set);
 
@@ -7733,39 +7728,71 @@
         break;
     }
 
+    if (warn_on_fwd_ref) {
+        /* hide errors, we can print only warnings */
+        ly_vlog_hide(1);
+    }
+
     /* check "when" */
     if (when) {
         resolve_when_ctx_snode(node, &ctx_snode, &ctx_snode_type);
         if (lyxp_atomize(when->cond, ctx_snode, ctx_snode_type, &tmp_set, LYXP_SNODE_WHEN | opts)) {
             free(tmp_set.val.snodes);
-            LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Resolving when condition \"%s\" failed.", when->cond);
-            if ((ly_errno == LY_EVALID) && (ly_vecode == LYVE_XPATH_INSNODE)) {
-                return EXIT_FAILURE;
-            } else {
-                return -1;
+            if ((ly_errno != LY_EVALID) || (ly_vecode != LYVE_XPATH_INSNODE)) {
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Invalid when condition \"%s\".", when->cond);
+                ret = -1;
+                goto finish;
+            } else if (!warn_on_fwd_ref) {
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Invalid when condition \"%s\".", when->cond);
+                ret = EXIT_FAILURE;
+                goto finish;
             }
-        }
+            ly_vlog_hide(0);
+            LOGWRN(ly_errmsg());
+            LOGWRN("Invalid when condition \"%s\".", when->cond);
+            ly_vlog_hide(1);
 
-        set_snode_merge(set, &tmp_set);
-        memset(&tmp_set, 0, sizeof tmp_set);
+            ret = EXIT_FAILURE;
+            memset(&tmp_set, 0, sizeof tmp_set);
+        } else {
+            set_snode_merge(set, &tmp_set);
+            memset(&tmp_set, 0, sizeof tmp_set);
+        }
     }
 
     /* check "must" */
     for (i = 0; i < must_size; ++i) {
         if (lyxp_atomize(must[i].expr, node, LYXP_NODE_ELEM, &tmp_set, LYXP_SNODE_MUST | opts)) {
             free(tmp_set.val.snodes);
-            free(set->val.snodes);
-            LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Resolving must restriction \"%s\" failed.", must[i].expr);
-            if ((ly_errno == LY_EVALID) && (ly_vecode == LYVE_XPATH_INSNODE)) {
-                return EXIT_FAILURE;
-            } else {
-                return -1;
+            if ((ly_errno != LY_EVALID) || (ly_vecode != LYVE_XPATH_INSNODE)) {
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Invalid must restriction \"%s\".", must[i].expr);
+                ret = -1;
+                goto finish;
+            } else if (!warn_on_fwd_ref) {
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "Invalid must restriction \"%s\".", must[i].expr);
+                ret = EXIT_FAILURE;
+                goto finish;
             }
-        }
+            ly_vlog_hide(0);
+            LOGWRN(ly_errmsg());
+            LOGWRN("Invalid must restriction \"%s\".", must[i].expr);
+            ly_vlog_hide(1);
 
-        set_snode_merge(set, &tmp_set);
-        memset(&tmp_set, 0, sizeof tmp_set);
+            ret = EXIT_FAILURE;
+            memset(&tmp_set, 0, sizeof tmp_set);
+        } else {
+            set_snode_merge(set, &tmp_set);
+            memset(&tmp_set, 0, sizeof tmp_set);
+        }
     }
 
-    return EXIT_SUCCESS;
+finish:
+    if (warn_on_fwd_ref) {
+        ly_vlog_hide(0);
+    }
+    if (ret) {
+        free(set->val.snodes);
+        memset(set, 0, sizeof *set);
+    }
+    return ret;
 }
diff --git a/src/xpath.h b/src/xpath.h
index 865c5f0..89e8f09 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -253,10 +253,12 @@
  * @param[in] node Node to examine.
  * @param[in,out] set Resulting set of atoms merged from all the expressions.
  * Will be cleared before use.
+ * @param[in] warn_on_fwd_ref Setting this flag causes no errors to be printed and
+ * only warning is printed on forward reference paths (addressing a non-existing node).
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
-int lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set);
+int lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set, int warn_on_fwd_ref);
 
 /**
  * @brief Cast XPath set to another type.