libyang UPDATE optional value validation and context type plugins (#2171)

This patch separates the build-in type validations from store
operations to allow storing a node even if the value doesn't pass the
validations. To do multiple changes were done:
 - introduces LY_CTX_BASIC_PLUGINS_ONLY flag, which prevents loading of
   any advanced plugins
 - introduces LYPLG_TYPE_STORE_ONLY flag, which skip validation and
   perform just storing
 - introduces LYD_PARSE_STORE_ONLY flag, which implies usage of LYPLG_TYPE_STORE_ONLY
 - introduces options for lyd_new_* API
 - removes lyd_new_(term|list)_(bin|canon) API
 - added sanity checks within lyd_new_(term|list) APIs for proper
   combinations of options
 - refactored lyd_new_* APIs to use common flags to use common options attributes
diff --git a/src/context.c b/src/context.c
index a7902e9..97ba672 100644
--- a/src/context.c
+++ b/src/context.c
@@ -283,6 +283,7 @@
     struct ly_in *in = NULL;
     LY_ERR rc = LY_SUCCESS;
     struct lys_glob_unres unres = {0};
+    ly_bool builtin_plugins_only;
 
     LY_CHECK_ARG_RET(NULL, new_ctx, LY_EINVAL);
 
@@ -293,7 +294,8 @@
     lydict_init(&ctx->dict);
 
     /* plugins */
-    LY_CHECK_ERR_GOTO(lyplg_init(), LOGINT(NULL); rc = LY_EINT, cleanup);
+    builtin_plugins_only = (options & LY_CTX_BUILTIN_PLUGINS_ONLY) ? 1 : 0;
+    LY_CHECK_ERR_GOTO(lyplg_init(builtin_plugins_only), LOGINT(NULL); rc = LY_EINT, cleanup);
 
     if (options & LY_CTX_LEAFREF_LINKING) {
         ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
@@ -1234,8 +1236,7 @@
         LY_CHECK_GOTO(ret = ylib_deviation(cont, mod, 0), error);
 
         /* conformance-type */
-        LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "conformance-type", mod->implemented ? "implement" : "import", 0,
-                NULL), error);
+        LY_CHECK_GOTO(ret = lyd_new_term(cont, NULL, "conformance-type", mod->implemented ? "implement" : "import", 0, NULL), error);
 
         /* submodule list */
         LY_CHECK_GOTO(ret = ylib_submodules(cont, mod->parsed, 0), error);
diff --git a/src/context.h b/src/context.h
index 8e8b205..9f1b8e6 100644
--- a/src/context.h
+++ b/src/context.h
@@ -202,6 +202,13 @@
                                         'require-instance false;'. It also enables usage of
                                         [lyd_leafref_get_links](@ref lyd_leafref_get_links) and
                                         [lyd_leafref_link_node_tree](@ref lyd_leafref_link_node_tree) APIs. */
+#define LY_CTX_BUILTIN_PLUGINS_ONLY 0x0800 /**< By default, context loads all available built-in plugins and extensions. This
+                                        options prohibits loading of built-in non-YANG plugin types and extensions (ipv4-address,
+                                        ipv6-address, etc.). Instead the value is processed by built-in YANG plugins (usually string)
+                                        with all its behavioral implications as hex-string comparison becoming case-sensitive.
+                                        Change of this flag during the lifetime of context is not fully supported. Once the non-YANG
+                                        plugins or extensions are loaded during context creation, they will be used regardless of this
+                                        flag. Therefore it is recommended to set this flag during the first context creation. */
 
 /** @} contextoptions */
 
diff --git a/src/diff.c b/src/diff.c
index 079c898..744f039 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -154,7 +154,7 @@
     }
 
     /* create the metadata */
-    LY_CHECK_GOTO(rc = lyd_new_meta(NULL, node, NULL, meta_name, meta_val, 0, NULL), cleanup);
+    LY_CHECK_GOTO(rc = lyd_new_meta(NULL, node, NULL, meta_name, meta_val, LYD_NEW_VAL_STORE_ONLY, NULL), cleanup);
 
 cleanup:
     free(dyn);
@@ -382,7 +382,7 @@
             }
 
             /* set the none operation */
-            LY_CHECK_RET(lyd_new_meta(NULL, elem, NULL, "yang:operation", "none", 0, NULL));
+            LY_CHECK_RET(lyd_new_meta(NULL, elem, NULL, "yang:operation", "none", LYD_NEW_VAL_STORE_ONLY, NULL));
         }
 
         dup = diff_parent;
@@ -424,12 +424,12 @@
 
         /* add parent operation, if any */
         if (diff_parent && (diff_parent != dup)) {
-            LY_CHECK_RET(lyd_new_meta(NULL, diff_parent, NULL, "yang:operation", "none", 0, NULL));
+            LY_CHECK_RET(lyd_new_meta(NULL, diff_parent, NULL, "yang:operation", "none", LYD_NEW_VAL_STORE_ONLY, NULL));
         }
     }
 
     /* add subtree operation */
-    LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:operation", lyd_diff_op2str(op), 0, NULL));
+    LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:operation", lyd_diff_op2str(op), LYD_NEW_VAL_STORE_ONLY, NULL));
 
     if (op == LYD_DIFF_OP_CREATE) {
         /* all nested user-ordered (leaf-)lists need special metadata for create op */
@@ -443,37 +443,37 @@
 
     /* orig-default */
     if (orig_default) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-default", orig_default, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-default", orig_default, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* orig-value */
     if (orig_value) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-value", orig_value, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-value", orig_value, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* key */
     if (key) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:key", key, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:key", key, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* value */
     if (value) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:value", value, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:value", value, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* position */
     if (position) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:position", position, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:position", position, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* orig-key */
     if (orig_key) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-key", orig_key, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-key", orig_key, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     /* orig-position */
     if (orig_position) {
-        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-position", orig_position, 0, NULL));
+        LY_CHECK_RET(lyd_new_meta(NULL, dup, NULL, "yang:orig-position", orig_position, LYD_NEW_VAL_STORE_ONLY, NULL));
     }
 
     return LY_SUCCESS;
@@ -1460,7 +1460,7 @@
     lyd_diff_del_meta(node, "operation");
 
     if (node->schema) {
-        return lyd_new_meta(LYD_CTX(node), node, NULL, "yang:operation", lyd_diff_op2str(op), 0, NULL);
+        return lyd_new_meta(LYD_CTX(node), node, NULL, "yang:operation", lyd_diff_op2str(op), LYD_NEW_VAL_STORE_ONLY, NULL);
     } else {
         return lyd_new_attr(node, "yang", "operation", lyd_diff_op2str(op), NULL);
     }
@@ -1685,7 +1685,7 @@
 
                 /* current value is the previous one (meta) */
                 LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-value",
-                        lyd_get_value(*diff_match), 0, NULL));
+                        lyd_get_value(*diff_match), LYD_NEW_VAL_STORE_ONLY, NULL));
 
                 /* update the value itself */
                 LY_CHECK_RET(lyd_change_term(*diff_match, lyd_get_value(src_diff)));
@@ -1699,10 +1699,10 @@
                 to_free = *diff_match;
                 *diff_match = src_dup;
 
-                r = lyd_new_meta(ctx, src_dup, NULL, "yang:orig-value", lyd_get_value(to_free), 0, NULL);
+                r = lyd_new_meta(ctx, src_dup, NULL, "yang:orig-value", lyd_get_value(to_free), LYD_NEW_VAL_STORE_ONLY, NULL);
                 lyd_free_tree(to_free);
                 LY_CHECK_RET(r);
-                LY_CHECK_RET(lyd_new_meta(ctx, src_dup, NULL, "yang:operation", lyd_diff_op2str(LYD_DIFF_OP_REPLACE), 0, NULL));
+                LY_CHECK_RET(lyd_new_meta(ctx, src_dup, NULL, "yang:operation", lyd_diff_op2str(LYD_DIFF_OP_REPLACE), LYD_NEW_VAL_STORE_ONLY, NULL));
             }
         } else {
             /* deleted + created -> operation NONE */
@@ -1713,7 +1713,7 @@
         if ((*diff_match)->schema->nodetype & LYD_NODE_TERM) {
             /* add orig-dflt metadata */
             LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-default",
-                    trg_flags & LYD_DEFAULT ? "true" : "false", 0, NULL));
+                    trg_flags & LYD_DEFAULT ? "true" : "false", LYD_NEW_VAL_STORE_ONLY, NULL));
 
             /* update dflt flag itself */
             (*diff_match)->flags &= ~LYD_DEFAULT;
@@ -1763,7 +1763,7 @@
         if (diff_match->schema->nodetype & LYD_NODE_TERM) {
             /* add orig-default meta because it is expected */
             LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-default",
-                    src_diff->flags & LYD_DEFAULT ? "true" : "false", 0, NULL));
+                    src_diff->flags & LYD_DEFAULT ? "true" : "false", LYD_NEW_VAL_STORE_ONLY, NULL));
         }
         break;
     case LYD_DIFF_OP_REPLACE:
diff --git a/src/parser_common.c b/src/parser_common.c
index dadd1d7..06544f1 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -284,8 +284,10 @@
 {
     LY_ERR r;
     ly_bool incomplete;
+    ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) ? 1 : 0;
 
-    if ((r = lyd_create_term(schema, value, value_len, 1, dynamic, format, prefix_data, hints, &incomplete, node))) {
+    if ((r = lyd_create_term(schema, value, value_len, 1, store_only, dynamic, format, prefix_data,
+            hints, &incomplete, node))) {
         if (lydctx->data_ctx->ctx != schema->module->ctx) {
             /* move errors to the main context */
             ly_err_move(schema->module->ctx, (struct ly_ctx *)lydctx->data_ctx->ctx);
@@ -308,6 +310,7 @@
     char *dpath = NULL, *path = NULL;
     ly_bool incomplete;
     struct lyd_meta *first = NULL;
+    ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) ? 1 : 0;
 
     if (meta && *meta) {
         /* remember the first metadata */
@@ -323,7 +326,7 @@
     }
     ly_log_location(NULL, NULL, path, NULL);
 
-    LY_CHECK_GOTO(rc = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, 1, dynamic, format,
+    LY_CHECK_GOTO(rc = lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, 1, store_only, dynamic, format,
             prefix_data, hints, ctx_node, 0, &incomplete), cleanup);
 
     if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
diff --git a/src/parser_data.h b/src/parser_data.h
index 8b61633..e782b47 100644
--- a/src/parser_data.h
+++ b/src/parser_data.h
@@ -134,6 +134,7 @@
  * - when statements on existing nodes are evaluated, if not satisfied, a validation error is raised,
  * - invalid multiple data instances/data from several cases cause a validation error,
  * - implicit nodes (NP containers and default values) are added.
+ * - Validations based on leaf/leaf-list types restriction is being done regardless of setting LYD_PARSE_ONLY
  * @{
  */
 /* note: keep the lower 16bits free for use by LYD_VALIDATE_ flags. They are not supposed to be combined together,
@@ -171,6 +172,8 @@
 #define LYD_PARSE_NO_NEW 0x1000000          /**< Do not set ::LYD_NEW (non-validated node flag) for any nodes. Use
                                                  when parsing validated data to skip some validation tasks and modify
                                                  some validation behavior (auto-deletion of cases). */
+#define LYD_PARSE_STORE_ONLY 0x2000000      /**< Perform only storing operation, no validation based on leaf/leaf-list type
+                                                 restrictions will be performed. */
 
 #define LYD_PARSE_OPTS_MASK 0xFFFF0000      /**< Mask for all the LYD_PARSE_ options. */
 
diff --git a/src/path.c b/src/path.c
index 2214ed0..5fd33e6 100644
--- a/src/path.c
+++ b/src/path.c
@@ -710,8 +710,8 @@
                 if (key) {
                     LOG_LOCSET(key, NULL);
                 }
-                ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, NULL,
-                        format, prefix_data, LYD_HINT_DATA, key, NULL);
+                ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, 0,
+                        NULL, format, prefix_data, LYD_HINT_DATA, key, NULL);
                 LOG_LOCBACK(key ? 1 : 0, 0);
                 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
 
@@ -776,8 +776,8 @@
         if (ctx_node) {
             LOG_LOCSET(ctx_node, NULL);
         }
-        ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, NULL,
-                format, prefix_data, LYD_HINT_DATA, ctx_node, NULL);
+        ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, 0,
+                NULL, format, prefix_data, LYD_HINT_DATA, ctx_node, NULL);
         LOG_LOCBACK(ctx_node ? 1 : 0, 0);
         LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
         ++(*tok_idx);
@@ -1356,7 +1356,7 @@
             case LY_PATH_PREDTYPE_LIST_VAR:
             case LY_PATH_PREDTYPE_LIST:
                 /* we will use hashes to find one list instance */
-                LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
+                LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, 1, &target));
                 lyd_find_sibling_first(start, target, &node);
                 lyd_free_tree(target);
                 break;
diff --git a/src/plugins.c b/src/plugins.c
index c1bdad5..1f76049 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -444,7 +444,7 @@
 #endif
 
 LY_ERR
-lyplg_init(void)
+lyplg_init(ly_bool builtin_plugins_only)
 {
     LY_ERR ret;
 
@@ -470,34 +470,36 @@
     LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
     LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
 
-    /* yang */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
+    if (!builtin_plugins_only) {
+        /* yang */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
 
-    /* ietf-inet-types */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
+        /* ietf-inet-types */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
 
-    /* ietf-yang-types */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
+        /* ietf-yang-types */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
 
-    /* ietf-netconf-acm */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
+        /* ietf-netconf-acm */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
 
-    /* lyds_tree */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error);
+        /* lyds_tree */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error);
 
-    /* internal extensions */
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
-    LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
+        /* internal extensions */
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
+        LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
+    }
 
 #ifndef STATIC
     /* external types */
diff --git a/src/plugins_internal.h b/src/plugins_internal.h
index d13db16..f624624 100644
--- a/src/plugins_internal.h
+++ b/src/plugins_internal.h
@@ -48,11 +48,12 @@
  *
  * Covers both the types and extensions plugins.
  *
+ * @param[in] builtin_plugins_only Whether to load only built-in YANG plugin types and extensions.
  * @return LY_SUCCESS in case of success
  * @return LY_EINT in case of internal error
  * @return LY_EMEM in case of memory allocation failure.
  */
-LY_ERR lyplg_init(void);
+LY_ERR lyplg_init(ly_bool builtin_plugins_only);
 
 /**
  * @brief Remove (unload) all the plugins currently available.
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 4b8b1b9..184393c 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -475,6 +475,7 @@
 #define LYPLG_TYPE_STORE_IMPLEMENT 0x02 /**< If a foreign module is needed to be implemented to successfully instantiate
                                              the value, make the module implemented. */
 #define LYPLG_TYPE_STORE_IS_UTF8   0x04 /**< The value is guaranteed to be a valid UTF-8 string, if applicable for the type. */
+#define LYPLG_TYPE_STORE_ONLY      0x08 /**< The value is stored only. The validation must be done using [validate](@ref lyplg_type_validate_clb) */
 /** @} plugintypestoreopts */
 
 /**
diff --git a/src/plugins_types/binary.c b/src/plugins_types/binary.c
index a801144..c265511 100644
--- a/src/plugins_types/binary.c
+++ b/src/plugins_types/binary.c
@@ -42,6 +42,8 @@
  */
 static const char b64_etable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
+static LY_ERR lyplg_type_validate_binary(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
+
 /**
  * @brief Encode binary value into a base64 string value.
  *
@@ -165,12 +167,11 @@
  *
  * @param[in] value Value to validate.
  * @param[in] value_len Length of @p value.
- * @param[in] type type of the value.
  * @param[out] err Error information.
  * @return LY_ERR value.
  */
 static LY_ERR
-binary_base64_validate(const char *value, size_t value_len, const struct lysc_type_bin *type, struct ly_err_item **err)
+binary_base64_validate(const char *value, size_t value_len, struct ly_err_item **err)
 {
     uint32_t idx, pad;
 
@@ -204,13 +205,6 @@
         return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Base64 encoded value length must be divisible by 4.");
     }
 
-    /* length restriction of the binary value */
-    if (type->length) {
-        const uint32_t octet_count = ((idx + pad) / 4) * 3 - pad;
-
-        LY_CHECK_RET(lyplg_type_validate_range(LY_TYPE_BINARY, type->length, octet_count, value, value_len, err));
-    }
-
     return LY_SUCCESS;
 }
 
@@ -266,7 +260,6 @@
         struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
     struct lyd_value_binary *val;
 
     /* init storage */
@@ -306,7 +299,7 @@
         LY_CHECK_GOTO(ret, cleanup);
 
         /* validate */
-        ret = binary_base64_validate(value, value_len, type_bin, err);
+        ret = binary_base64_validate(value, value_len, err);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -324,6 +317,12 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
+    if (!(options & LYPLG_TYPE_STORE_ONLY)) {
+        /* validate value */
+        ret = lyplg_type_validate_binary(ctx, type, NULL, NULL, storage, err);
+        LY_CHECK_GOTO(ret, cleanup);
+    }
+
 cleanup:
     if (options & LYPLG_TYPE_STORE_DYNAMIC) {
         free((void *)value);
@@ -335,6 +334,33 @@
     return ret;
 }
 
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the binary type.
+ */
+static LY_ERR
+lyplg_type_validate_binary(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
+        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
+{
+    struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
+    struct lyd_value_binary *val;
+    const void *value;
+    size_t value_len;
+
+    LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
+
+    val = LYPLG_TYPE_VAL_IS_DYN(val) ? (struct lyd_value_binary *)(storage->dyn_mem) : (struct lyd_value_binary *)(storage->fixed_mem);
+    value = storage->_canonical;
+    value_len = strlen(storage->_canonical);
+    *err = NULL;
+
+    /* length restriction of the binary value */
+    if (type_bin->length) {
+        LY_CHECK_RET(lyplg_type_validate_range(LY_TYPE_BINARY, type_bin->length, val->size, value, value_len, err));
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyplg_type_compare_binary(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
 {
@@ -470,7 +496,7 @@
 
         .plugin.id = "libyang 2 - binary, version 1",
         .plugin.store = lyplg_type_store_binary,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_binary,
         .plugin.compare = lyplg_type_compare_binary,
         .plugin.sort = lyplg_type_sort_binary,
         .plugin.print = lyplg_type_print_binary,
diff --git a/src/plugins_types/decimal64.c b/src/plugins_types/decimal64.c
index 9edc968..0eb01a0 100644
--- a/src/plugins_types/decimal64.c
+++ b/src/plugins_types/decimal64.c
@@ -33,6 +33,8 @@
  * | 8        | yes | `int64_t *` | little-endian value represented without floating point |
  */
 
+static LY_ERR lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
+
 /**
  * @brief Convert decimal64 number to canonical string.
  *
@@ -140,10 +142,9 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
-    if (type_dec->range) {
-        /* check range of the number */
-        ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
-                strlen(storage->_canonical), err);
+    if (!(options & LYPLG_TYPE_STORE_ONLY)) {
+        /* validate value */
+        ret = lyplg_type_validate_decimal64(ctx, type, NULL, NULL, storage, err);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -158,6 +159,31 @@
     return ret;
 }
 
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the built-in decimal64 type.
+ */
+static LY_ERR
+lyplg_type_validate_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
+        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    struct lysc_type_dec *type_dec = (struct lysc_type_dec *)type;
+    int64_t num;
+
+    LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
+    *err = NULL;
+    num = storage->dec64;
+
+    if (type_dec->range) {
+        /* check range of the number */
+        ret = lyplg_type_validate_range(type->basetype, type_dec->range, num, storage->_canonical,
+                strlen(storage->_canonical), err);
+        LY_CHECK_RET(ret);
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyplg_type_compare_decimal64(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
         const struct lyd_value *val2)
@@ -236,7 +262,7 @@
 
         .plugin.id = "libyang 2 - decimal64, version 1",
         .plugin.store = lyplg_type_store_decimal64,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_decimal64,
         .plugin.compare = lyplg_type_compare_decimal64,
         .plugin.sort = lyplg_type_sort_decimal64,
         .plugin.print = lyplg_type_print_decimal64,
diff --git a/src/plugins_types/integer.c b/src/plugins_types/integer.c
index 73c4533..eb66499 100644
--- a/src/plugins_types/integer.c
+++ b/src/plugins_types/integer.c
@@ -36,6 +36,9 @@
  * | 1/2/4/8 | yes | pointer to the specific integer type | little-endian integer value |
  */
 
+static LY_ERR lyplg_type_validate_int(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
+static LY_ERR lyplg_type_validate_uint(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
+
 /**
  * @brief LYB value size of each integer type.
  */
@@ -54,7 +57,6 @@
     int64_t num = 0;
     int base = 1;
     char *canon = NULL;
-    struct lysc_type_num *type_num = (struct lysc_type_num *)type;
 
     /* init storage */
     memset(storage, 0, sizeof *storage);
@@ -154,10 +156,9 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
-    /* validate range of the number */
-    if (type_num->range) {
-        ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
-                strlen(storage->_canonical), err);
+    if (!(options & LYPLG_TYPE_STORE_ONLY)) {
+        /* validate value */
+        ret = lyplg_type_validate_int(ctx, type, NULL, NULL, storage, err);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -172,6 +173,48 @@
     return ret;
 }
 
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the signed interger types.
+ */
+static LY_ERR
+lyplg_type_validate_int(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
+        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    struct lysc_type_num *type_num = (struct lysc_type_num *)type;
+    int64_t num;
+
+    LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
+    *err = NULL;
+
+    /* set the value (matters for big-endian) and get the correct int64 number */
+    switch (type->basetype) {
+    case LY_TYPE_INT8:
+        num = storage->int8;
+        break;
+    case LY_TYPE_INT16:
+        num = storage->int16;
+        break;
+    case LY_TYPE_INT32:
+        num = storage->int32;
+        break;
+    case LY_TYPE_INT64:
+        num = storage->int64;
+        break;
+    default:
+        return LY_EINVAL;
+    }
+
+    /* validate range of the number */
+    if (type_num->range) {
+        ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
+                strlen(storage->_canonical), err);
+        LY_CHECK_RET(ret);
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyplg_type_compare_int(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
 {
@@ -318,7 +361,6 @@
     uint64_t num = 0;
     int base = 0;
     char *canon;
-    struct lysc_type_num *type_num = (struct lysc_type_num *)type;
 
     /* init storage */
     memset(storage, 0, sizeof *storage);
@@ -398,10 +440,9 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
-    /* validate range of the number */
-    if (type_num->range) {
-        ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
-                strlen(storage->_canonical), err);
+    if (!(options & LYPLG_TYPE_STORE_ONLY)) {
+        /* validate value */
+        ret = lyplg_type_validate_uint(ctx, type, NULL, NULL, storage, err);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -416,6 +457,48 @@
     return ret;
 }
 
+/**
+ * @brief Implementation of ::lyplg_type_validate_clb for the unsigned interger types.
+ */
+static LY_ERR
+lyplg_type_validate_uint(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
+        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    struct lysc_type_num *type_num = (struct lysc_type_num *)type;
+    uint64_t num;
+
+    LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
+    *err = NULL;
+
+    /* set the value (matters for big-endian) and get the correct int64 number */
+    switch (type->basetype) {
+    case LY_TYPE_UINT8:
+        num = storage->uint8;
+        break;
+    case LY_TYPE_UINT16:
+        num = storage->uint16;
+        break;
+    case LY_TYPE_UINT32:
+        num = storage->uint32;
+        break;
+    case LY_TYPE_UINT64:
+        num = storage->uint64;
+        break;
+    default:
+        return LY_EINVAL;
+    }
+
+    /* validate range of the number */
+    if (type_num->range) {
+        ret = lyplg_type_validate_range(type->basetype, type_num->range, num, storage->_canonical,
+                strlen(storage->_canonical), err);
+        LY_CHECK_RET(ret);
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyplg_type_compare_uint(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1, const struct lyd_value *val2)
 {
@@ -563,7 +646,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_uint,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_uint,
         .plugin.compare = lyplg_type_compare_uint,
         .plugin.sort = lyplg_type_sort_uint,
         .plugin.print = lyplg_type_print_uint,
@@ -577,7 +660,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_uint,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_uint,
         .plugin.compare = lyplg_type_compare_uint,
         .plugin.sort = lyplg_type_sort_uint,
         .plugin.print = lyplg_type_print_uint,
@@ -591,7 +674,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_uint,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_uint,
         .plugin.compare = lyplg_type_compare_uint,
         .plugin.sort = lyplg_type_sort_uint,
         .plugin.print = lyplg_type_print_uint,
@@ -605,7 +688,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_uint,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_uint,
         .plugin.compare = lyplg_type_compare_uint,
         .plugin.sort = lyplg_type_sort_uint,
         .plugin.print = lyplg_type_print_uint,
@@ -619,7 +702,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_int,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_int,
         .plugin.compare = lyplg_type_compare_int,
         .plugin.sort = lyplg_type_sort_int,
         .plugin.print = lyplg_type_print_int,
@@ -633,7 +716,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_int,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_int,
         .plugin.compare = lyplg_type_compare_int,
         .plugin.sort = lyplg_type_sort_int,
         .plugin.print = lyplg_type_print_int,
@@ -647,7 +730,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_int,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_int,
         .plugin.compare = lyplg_type_compare_int,
         .plugin.sort = lyplg_type_sort_int,
         .plugin.print = lyplg_type_print_int,
@@ -661,7 +744,7 @@
 
         .plugin.id = "libyang 2 - integers, version 1",
         .plugin.store = lyplg_type_store_int,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_int,
         .plugin.compare = lyplg_type_compare_int,
         .plugin.sort = lyplg_type_sort_int,
         .plugin.print = lyplg_type_print_int,
diff --git a/src/plugins_types/string.c b/src/plugins_types/string.c
index 5ae5204..e4c1cb9 100644
--- a/src/plugins_types/string.c
+++ b/src/plugins_types/string.c
@@ -34,6 +34,8 @@
  * | string length | yes | `char *` | string itself |
  */
 
+static LY_ERR lyplg_type_validate_string(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node), const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err);
+
 /**
  * @brief Check string value for invalid characters.
  *
@@ -64,7 +66,6 @@
         struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
-    struct lysc_type_str *type_str = (struct lysc_type_str *)type;
 
     /* init storage */
     memset(storage, 0, sizeof *storage);
@@ -80,17 +81,6 @@
     ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
     LY_CHECK_GOTO(ret, cleanup);
 
-    /* length restriction of the string */
-    if (type_str->length) {
-        /* value_len is in bytes, but we need number of characters here */
-        ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err);
-        LY_CHECK_GOTO(ret, cleanup);
-    }
-
-    /* pattern restrictions */
-    ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
-    LY_CHECK_GOTO(ret, cleanup);
-
     /* store canonical value */
     if (options & LYPLG_TYPE_STORE_DYNAMIC) {
         ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
@@ -101,6 +91,12 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
+    if (!(options & LYPLG_TYPE_STORE_ONLY)) {
+        /* validate value */
+        ret = lyplg_type_validate_string(ctx, type, NULL, NULL, storage, err);
+        LY_CHECK_GOTO(ret, cleanup);
+    }
+
 cleanup:
     if (options & LYPLG_TYPE_STORE_DYNAMIC) {
         free((void *)value);
@@ -113,6 +109,37 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_validate_clb for the string type.
+ */
+static LY_ERR
+lyplg_type_validate_string(const struct ly_ctx *UNUSED(ctx), const struct lysc_type *type, const struct lyd_node *UNUSED(ctx_node),
+        const struct lyd_node *UNUSED(tree), struct lyd_value *storage, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    struct lysc_type_str *type_str = (struct lysc_type_str *)type;
+    const void *value;
+    size_t value_len;
+
+    LY_CHECK_ARG_RET(NULL, type, storage, err, LY_EINVAL);
+    value = storage->_canonical;
+    value_len = strlen(storage->_canonical);
+    *err = NULL;
+
+    /* length restriction of the string */
+    if (type_str->length) {
+        /* value_len is in bytes, but we need number of characters here */
+        ret = lyplg_type_validate_range(LY_TYPE_STRING, type_str->length, ly_utf8len(value, value_len), value, value_len, err);
+        LY_CHECK_RET(ret);
+    }
+
+    /* pattern restrictions */
+    ret = lyplg_type_validate_patterns(type_str->patterns, value, value_len, err);
+    LY_CHECK_RET(ret);
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Plugin information for string type implementation.
  *
  * Note that external plugins are supposed to use:
@@ -127,7 +154,7 @@
 
         .plugin.id = "libyang 2 - string, version 1",
         .plugin.store = lyplg_type_store_string,
-        .plugin.validate = NULL,
+        .plugin.validate = lyplg_type_validate_string,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.sort = lyplg_type_sort_simple,
         .plugin.print = lyplg_type_print_simple,
diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c
index 32c682c..8dbc68b 100644
--- a/src/plugins_types/union.c
+++ b/src/plugins_types/union.c
@@ -156,6 +156,7 @@
  * @param[in] ctx libyang context.
  * @param[in] type Specific union type to use for storing.
  * @param[in] subvalue Union subvalue structure.
+ * @param[in] options The store options.
  * @param[in] resolve Whether the value needs to be resolved (validated by a callback).
  * @param[in] ctx_node Context node for prefix resolution.
  * @param[in] tree Data tree for resolving (validation).
@@ -164,13 +165,14 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value_union *subvalue,
+union_store_type(const struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value_union *subvalue, uint32_t options,
         ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lys_glob_unres *unres,
         struct ly_err_item **err)
 {
     LY_ERR ret;
     const void *value = NULL;
     size_t value_len = 0;
+    uint32_t opts;
 
     *err = NULL;
 
@@ -181,7 +183,8 @@
         value_len = subvalue->orig_len;
     }
 
-    ret = type->plugin->store(ctx, type, value, value_len, 0, subvalue->format, subvalue->prefix_data, subvalue->hints,
+    opts = (options & LYPLG_TYPE_STORE_ONLY) ? LYPLG_TYPE_STORE_ONLY : 0;
+    ret = type->plugin->store(ctx, type, value, value_len, opts, subvalue->format, subvalue->prefix_data, subvalue->hints,
             subvalue->ctx_node, &subvalue->value, unres, err);
     if ((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE)) {
         /* clear any leftover/freed garbage */
@@ -207,6 +210,7 @@
  * @param[in] ctx libyang context.
  * @param[in] types Sized array of union types.
  * @param[in] subvalue Union subvalue structure.
+ * @param[in] options The store options.
  * @param[in] resolve Whether the value needs to be resolved (validated by a callback).
  * @param[in] ctx_node Context node for prefix resolution.
  * @param[in] tree Data tree for resolving (validation).
@@ -217,8 +221,8 @@
  */
 static LY_ERR
 union_find_type(const struct ly_ctx *ctx, struct lysc_type **types, struct lyd_value_union *subvalue,
-        ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree, uint32_t *type_idx,
-        struct lys_glob_unres *unres, struct ly_err_item **err)
+        uint32_t options, ly_bool resolve, const struct lyd_node *ctx_node, const struct lyd_node *tree,
+        uint32_t *type_idx, struct lys_glob_unres *unres, struct ly_err_item **err)
 {
     LY_ERR ret = LY_SUCCESS;
     LY_ARRAY_COUNT_TYPE u;
@@ -242,7 +246,7 @@
 
     /* use the first usable subtype to store the value */
     for (u = 0; u < LY_ARRAY_COUNT(types); ++u) {
-        ret = union_store_type(ctx, types[u], subvalue, resolve, ctx_node, tree, unres, &e);
+        ret = union_store_type(ctx, types[u], subvalue, options, resolve, ctx_node, tree, unres, &e);
         if ((ret == LY_SUCCESS) || (ret == LY_EINCOMPLETE)) {
             break;
         }
@@ -330,7 +334,7 @@
     }
 
     /* use the specific type to store the value */
-    ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 0, NULL, NULL, unres, err);
+    ret = union_store_type(ctx, type_u->types[type_idx], subvalue, *options, 0, NULL, NULL, unres, err);
 
     return ret;
 }
@@ -368,7 +372,7 @@
         LY_CHECK_GOTO(ret, cleanup);
 
         /* use the first usable subtype to store the value */
-        ret = union_find_type(ctx, type_u->types, subvalue, 0, NULL, NULL, NULL, unres, err);
+        ret = union_find_type(ctx, type_u->types, subvalue, options, 0, NULL, NULL, NULL, unres, err);
         LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup);
     }
 
@@ -406,11 +410,11 @@
     if (subvalue->format == LY_VALUE_LYB) {
         /* use the specific type to store the value */
         lyb_parse_union(subvalue->original, 0, &type_idx, NULL, NULL);
-        ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 1, ctx_node, tree, NULL, err);
+        ret = union_store_type(ctx, type_u->types[type_idx], subvalue, 0, 1, ctx_node, tree, NULL, err);
         LY_CHECK_RET(ret);
     } else {
         /* use the first usable subtype to store the value */
-        ret = union_find_type(ctx, type_u->types, subvalue, 1, ctx_node, tree, NULL, NULL, err);
+        ret = union_find_type(ctx, type_u->types, subvalue, 0, 1, ctx_node, tree, NULL, NULL, err);
         LY_CHECK_RET(ret);
     }
 
@@ -491,7 +495,7 @@
         ctx = subvalue->ctx_node->module->ctx;
     }
     subvalue->value.realtype->plugin->free(ctx, &subvalue->value);
-    r = union_find_type(ctx, type_u->types, subvalue, 0, NULL, NULL, &type_idx, NULL, &err);
+    r = union_find_type(ctx, type_u->types, subvalue, 0, 0, NULL, NULL, &type_idx, NULL, &err);
     ly_err_free(err);
     LY_CHECK_RET((r != LY_SUCCESS) && (r != LY_EINCOMPLETE), NULL);
 
diff --git a/src/tree_data.c b/src/tree_data.c
index a5f27a3..a9146d4 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1344,8 +1344,9 @@
 
 LY_ERR
 lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
-        size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format,
-        void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete)
+        size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic,
+        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt,
+        ly_bool *incomplete)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_ext_instance *ant = NULL;
@@ -1368,7 +1369,7 @@
     mt->parent = parent;
     mt->annotation = ant;
     lyplg_ext_get_storage(ant, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
-    ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, dynamic, format, prefix_data, hints,
+    ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, store_only, dynamic, format, prefix_data, hints,
             ctx_node, incomplete);
     LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
     ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
@@ -2138,7 +2139,7 @@
             /* store canonical value in the target context */
             val_can = lyd_get_value(node);
             type = ((struct lysc_node_leaf *)term->schema)->type;
-            ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, NULL, LY_VALUE_CANON, NULL,
+            ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, 1, NULL, LY_VALUE_CANON, NULL,
                     LYD_HINT_DATA, term->schema, NULL);
             LY_CHECK_GOTO(ret, error);
         }
@@ -2467,7 +2468,7 @@
 
         /* duplicate callback expect only the same contexts, so use the store callback */
         val_can = lyd_value_get_canonical(meta->annotation->module->ctx, &meta->value);
-        ret = lyd_value_store(parent_ctx, &mt->value, ant_type, val_can, strlen(val_can), 1, NULL,
+        ret = lyd_value_store(parent_ctx, &mt->value, ant_type, val_can, strlen(val_can), 1, 1, NULL,
                 LY_VALUE_CANON, NULL, LYD_HINT_DATA, parent->schema, NULL);
     } else {
         /* annotation */
@@ -3201,11 +3202,11 @@
         /* create a data node and find the instance */
         if (schema->nodetype == LYS_LEAFLIST) {
             /* target used attributes: schema, hash, value */
-            rc = lyd_create_term(schema, key_or_value, val_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target);
+            rc = lyd_create_term(schema, key_or_value, val_len, 0, 1, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target);
             LY_CHECK_RET(rc);
         } else {
             /* target used attributes: schema, hash, child (all keys) */
-            LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, &target));
+            LY_CHECK_RET(lyd_create_list2(schema, key_or_value, val_len, 1, &target));
         }
 
         /* find it */
diff --git a/src/tree_data.h b/src/tree_data.h
index a7ce4bf..9084f8e 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -282,11 +282,10 @@
  * - ::lyd_new_inner()
  * - ::lyd_new_term()
  * - ::lyd_new_term_bin()
- * - ::lyd_new_term_canon()
  * - ::lyd_new_list()
- * - ::lyd_new_list_bin()
- * - ::lyd_new_list_canon()
  * - ::lyd_new_list2()
+ * - ::lyd_new_list3()
+ * - ::lyd_new_list3_bin()
  * - ::lyd_new_any()
  * - ::lyd_new_opaq()
  * - ::lyd_new_opaq2()
@@ -1248,53 +1247,60 @@
 LIBYANG_API_DECL LY_ERR lyd_new_ext_inner(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node);
 
 /**
+ * @ingroup datatree
+ * @defgroup newvalueoptions New value creation options
+ *
+ * Various options to change lyd_new_*() behavior. The LYD_NEW_VAL* can be used within any API, others
+ * are API specific
+ *
+ * Default behavior:
+ * - the input data nodes or RPC/Action is taken into account
+ * - the value is being validated with all possible validations, which doesn't require existence of any other data nodes
+ * - the input value is expected to be in JSON format
+ * - if the target node already exists (and is not default), an error is returned.
+ * - the whole path to the target node is created (with any missing parents) if necessary.
+ * - RPC output schema children are completely ignored in all modules. Input is searched and nodes created normally.
+ * - during creation of new metadata, the nodes will have default flag set
+ * - value is copied and stored internally during any node creation
+ * @{
+ */
+
+#define LYD_NEW_VAL_OUTPUT 0x01      /**< Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
+                                          taken into consideration. Otherwise, the output's data node is going to be created. */
+#define LYD_NEW_VAL_STORE_ONLY 0x02  /**< Whether to perform only storing operation with no or minimum valitions */
+#define LYD_NEW_VAL_BIN_VALUE 0x04   /**< Interpret the provided leaf/leaf-list @p value as being in the binary
+                                          ::LY_VALUE_LYB format, to learn what exactly is expected see @ref howtoDataLYB. */
+#define LYD_NEW_VAL_CANON_VALUE 0x08 /**< Interpret the provided leaf/leaf-list @p value as being in the canonical
+                                          (or JSON if no defined) ::LY_VALUE_CANON format. If it is not, it may lead
+                                          to unexpected behavior. */
+#define LYD_NEW_META_CLEAR_DFLT 0x10 /**< Whether to clear the default flag starting from @p parent, recursively all NP containers. */
+#define LYD_NEW_PATH_UPDATE 0x20     /**< If the target node exists, is a leaf, and it is updated with a new value or its
+                                          default flag is changed, it is returned. If the target node exists and is not
+                                          a leaf or generally no change occurs in the @p parent tree, NULL is returned and
+                                          no error set. */
+#define LYD_NEW_PATH_OPAQ 0x40       /**< Enables the creation of opaque nodes with some specific rules. If the __last node__
+                                          in the path is not uniquely defined ((leaf-)list without a predicate) or has an
+                                          invalid value (leaf/leaf-list), it is created as opaque. */
+#define LYD_NEW_PATH_WITH_OPAQ 0x80  /**< Consider opaque nodes normally when searching for existing nodes. */
+#define LYD_NEW_ANY_USE_VALUE 0x100  /**< Whether to use dynamic @p value or make a copy. */
+
+/** @} newvalueoptions */
+
+/**
  * @brief Create a new list node in the data tree.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier
- * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for
- * key-less lists.
+ * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for key-less lists.
+ * In case of format set to LY_FORMAT_LYB, every key value must be followed by its length.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        ly_bool output, struct lyd_node **node, ...);
-
-/**
- * @brief Create a new list node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @param[in] ... Ordered binary key values of the new list instance, all must be set. Every key value must be followed
- * by its length. No keys are expected for key-less lists.
- * @return LY_ERR value.
- */
-LIBYANG_API_DECL LY_ERR lyd_new_list_bin(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        ly_bool output, struct lyd_node **node, ...);
-
-/**
- * @brief Create a new list node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @param[in] ... Ordered canonical key values of the new list instance, all must be set. No keys are expected for
- * key-less lists.
- * @return LY_ERR value.
- */
-LIBYANG_API_DECL LY_ERR lyd_new_list_canon(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        ly_bool output, struct lyd_node **node, ...);
+        uint32_t options, struct lyd_node **node, ...);
 
 /**
  * @brief Create a new top-level list node defined in the given extension instance.
@@ -1304,13 +1310,15 @@
  *
  * @param[in] ext Extension instance where the list node being created is defined.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node The created node.
  * @param[in] ... Ordered key values of the new list instance, all must be set. In case of an instance-identifier
- * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for
- * key-less lists.
+ * or identityref value, the JSON format is expected (module names instead of prefixes). No keys are expected for key-less lists.
+ * In case of format set to LY_FORMAT_LYB, every key value must be followed by its length.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node, ...);
+LIBYANG_API_DECL LY_ERR lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, uint32_t options,
+        struct lyd_node **node, ...);
 
 /**
  * @brief Create a new list node in the data tree.
@@ -1321,109 +1329,77 @@
  * @param[in] keys All key values predicate in the form of "[key1='val1'][key2='val2']...", they do not have to be ordered.
  * In case of an instance-identifier or identityref value, the JSON format is expected (module names instead of prefixes).
  * Use NULL or string of length 0 in case of key-less list.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char *keys, ly_bool output, struct lyd_node **node);
+        const char *keys, uint32_t options, struct lyd_node **node);
 
 /**
  * @brief Create a new list node in the data tree.
  *
+ * To create a term node based on binary value, use ::lyd_new_list3_bin().
+ *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
  * @param[in] key_values Ordered key string values of the new list instance, all must be set.
  * @param[in] value_lengths Array of lengths of each @p key_values, may be NULL if @p key_values are 0-terminated strings.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char **key_values, uint32_t *value_lengths, ly_bool output, struct lyd_node **node);
+        const char **key_values, uint32_t *value_lengths, uint32_t options, struct lyd_node **node);
 
 /**
- * @brief Create a new list node in the data tree.
+ * @brief Create a new list node in the data tree based on binary value.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] key_values Ordered key binary (LYB) values of the new list instance, all must be set.
- * @param[in] value_lengths Array of lengths of each @p key_values.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] key_values Ordered key string values of the new list instance, all must be set.
+ * @param[in] value_lengths Array of lengths of each @p key_values, may be NULL if @p key_values are 0-terminated strings.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_list3_bin(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const void **key_values, uint32_t *value_lengths, ly_bool output, struct lyd_node **node);
-
-/**
- * @brief Create a new list node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] key_values Ordered key canonical values of the new list instance, all must be set.
- * @param[in] value_lengths Array of lengths of each @p key_values, may be NULL if @p key_values are 0-terminated strings.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @return LY_ERR value.
- */
-LIBYANG_API_DECL LY_ERR lyd_new_list3_canon(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char **key_values, uint32_t *value_lengths, ly_bool output, struct lyd_node **node);
+        const void **key_values, uint32_t *value_lengths, uint32_t options, struct lyd_node **node);
 
 /**
  * @brief Create a new term node in the data tree.
  *
  * To create a top-level term node defined in an extension instance, use ::lyd_new_ext_term().
+ * To create a term node based on binary value, use ::lyd_new_term_bin().
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
- * @param[in] val_str String value of the node. If it varies based on the format, ::LY_VALUE_JSON is expected.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] value The value of the node in @p format.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char *val_str, ly_bool output, struct lyd_node **node);
+        const char *value, uint32_t options, struct lyd_node **node);
 
 /**
- * @brief Create a new term node in the data tree.
+ * @brief Create a new term node in the data tree based on binary value.
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
  * @param[in] value Binary value of the node. To learn what exactly is expected see @ref howtoDataLYB.
+ * @param[in] value The value of the node in @p format.
  * @param[in] value_len Length of @p value.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_term_bin(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const void *value, size_t value_len, ly_bool output, struct lyd_node **node);
-
-/**
- * @brief Create a new term node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
- * @param[in] val_str Canonical string value of the node. If it is not, it may lead to unexpected behavior.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @return LY_ERR value.
- */
-LIBYANG_API_DECL LY_ERR lyd_new_term_canon(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char *val_str, ly_bool output, struct lyd_node **node);
+        const void *value, size_t value_len, uint32_t options, struct lyd_node **node);
 
 /**
  * @brief Create a new top-level term node defined in the given extension instance.
@@ -1434,12 +1410,14 @@
  * @param[in] ext Extension instance where the term node being created is defined.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
  * @param[in] val_str String form of the value of the node being created. In case of an instance-identifier or identityref
- * value, the JSON format is expected (module names instead of prefixes).
+ * @param[in] value The value of the node in @p format. In case of an instance-identifier or identityref value,
+ * the JSON format is expected (module names instead of prefixes).
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node The created node.
  * @return LY_ERR value.
  */
-LIBYANG_API_DECL LY_ERR lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const char *val_str,
-        struct lyd_node **node);
+LIBYANG_API_DECL LY_ERR lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const void *value,
+        size_t value_len, uint32_t options, struct lyd_node **node);
 
 /**
  * @brief Create a new any node in the data tree.
@@ -1450,15 +1428,13 @@
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_ANYDATA or #LYS_ANYXML.
  * @param[in] value Value for the node. Expected type is determined by @p value_type.
- * @param[in] use_value Whether to use dynamic @p value or make a copy.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[in] value_type Type of the provided value in @p value.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const void *value, ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, ly_bool output, struct lyd_node **node);
+        const void *value, uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node);
 
 /**
  * @brief Create a new top-level any node defined in the given extension instance.
@@ -1469,13 +1445,13 @@
  * @param[in] ext Extension instance where the any node being created is defined.
  * @param[in] name Schema node name of the new data node. The node can be #LYS_ANYDATA or #LYS_ANYXML.
  * @param[in] value Value for the node. Expected type is determined by @p value_type.
- * @param[in] use_value Whether to use dynamic @p value or make a copy.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[in] value_type Type of the provided value in @p value.
  * @param[out] node The created node.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value,
-        ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node);
+        uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node);
 
 /**
  * @brief Create new metadata.
@@ -1487,26 +1463,26 @@
  *            If the prefix is specified it is always used but if not specified, @p module must be set.
  * @param[in] val_str String form of the value of the metadata. In case of an instance-identifier or identityref
  * value, the JSON format is expected (module names instead of prefixes).
- * @param[in] clear_dflt Whether to clear the default flag starting from @p parent, recursively all NP containers.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] meta Optional created metadata. Must be set if @p parent is NULL.
  * @return LY_ERR value.
  */
 LIBYANG_API_DECL LY_ERR lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys_module *module,
-        const char *name, const char *val_str, ly_bool clear_dflt, struct lyd_meta **meta);
+        const char *name, const char *val_str, uint32_t options, struct lyd_meta **meta);
 
 /**
  * @brief Create new metadata from an opaque node attribute if possible.
  *
  * @param[in] ctx libyang context.
  * @param[in] parent Optional parent node for the metadata being created. Must be set if @p meta is NULL.
- * @param[in] clear_dflt Whether to clear the default flag starting from @p parent, recursively all NP containers.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[in] attr Opaque node attribute to parse into metadata.
  * @param[out] meta Optional created metadata. Must be set if @p parent is NULL.
  * @return LY_SUCCESS on success.
  * @return LY_ENOT if the attribute could not be parsed into any metadata.
  * @return LY_ERR on error.
  */
-LIBYANG_API_DECL LY_ERR lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, ly_bool clear_dflt,
+LIBYANG_API_DECL LY_ERR lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t options,
         const struct lyd_attr *attr, struct lyd_meta **meta);
 
 /**
@@ -1571,37 +1547,6 @@
         struct lyd_attr **attr);
 
 /**
- * @ingroup datatree
- * @defgroup pathoptions Data path creation options
- *
- * Various options to change lyd_new_path*() behavior.
- *
- * Default behavior:
- * - if the target node already exists (and is not default), an error is returned.
- * - the whole path to the target node is created (with any missing parents) if necessary.
- * - RPC output schema children are completely ignored in all modules. Input is searched and nodes created normally.
- * @{
- */
-
-#define LYD_NEW_PATH_UPDATE 0x01    /**< If the target node exists, is a leaf, and it is updated with a new value or its
-                                        default flag is changed, it is returned. If the target node exists and is not
-                                        a leaf or generally no change occurs in the @p parent tree, NULL is returned and
-                                        no error set. */
-#define LYD_NEW_PATH_OUTPUT 0x02    /**< Changes the behavior to ignoring RPC/action input schema nodes and using only
-                                        output ones. */
-#define LYD_NEW_PATH_OPAQ   0x04    /**< Enables the creation of opaque nodes with some specific rules. If the __last node__
-                                        in the path is not uniquely defined ((leaf-)list without a predicate) or has an
-                                        invalid value (leaf/leaf-list), it is created as opaque. */
-#define LYD_NEW_PATH_BIN_VALUE 0x08 /**< Interpret the provided leaf/leaf-list @p value as being in the binary
-                                        ::LY_VALUE_LYB format, to learn what exactly is expected see @ref howtoDataLYB. */
-#define LYD_NEW_PATH_CANON_VALUE 0x10   /**< Interpret the provided leaf/leaf-list @p value as being in the canonical
-                                            (or JSON if no defined) ::LY_VALUE_CANON format. If it is not, it may lead
-                                            to unexpected behavior. */
-#define LYD_NEW_PATH_WITH_OPAQ 0x20 /**< Consider opaque nodes normally when searching for existing nodes. */
-
-/** @} pathoptions */
-
-/**
  * @brief Create a new node in the data tree based on a path. If creating anyxml/anydata nodes, ::lyd_new_path2
  * should be used instead, this function expects the value as string.
  *
@@ -1622,7 +1567,7 @@
  * @param[in] path [Path](@ref howtoXPath) to create.
  * @param[in] value String value of the new leaf/leaf-list. If it varies based on the format, ::LY_VALUE_JSON is expected.
  * For other node types, it should be NULL.
- * @param[in] options Bitmask of options, see @ref pathoptions.
+ * @param[in] options Bitmask of options, see @ref newvaloptions.
  * @param[out] node Optional first created node.
  * @return LY_SUCCESS on success.
  * @return LY_EEXIST if the final node to create exists (unless ::LYD_NEW_PATH_UPDATE is used).
@@ -1648,7 +1593,7 @@
  * @param[in] value_len Length of @p value in bytes. May be 0 if @p value is a zero-terminated string. Ignored when
  * creating anyxml/anydata nodes.
  * @param[in] value_type Anyxml/anydata node @p value type.
- * @param[in] options Bitmask of options, see @ref pathoptions.
+ * @param[in] options Bitmask of options, see @ref newvaloptions.
  * @param[out] new_parent Optional first parent node created. If only one node was created, equals to @p new_node.
  * @param[out] new_node Optional last node created.
  * @return LY_SUCCESS on success.
@@ -1675,7 +1620,7 @@
  * @param[in] ext Extension instance where the node being created is defined.
  * @param[in] path [Path](@ref howtoXPath) to create.
  * @param[in] value Value of the new leaf/leaf-list. For other node types, it should be NULL.
- * @param[in] options Bitmask of options, see @ref pathoptions.
+ * @param[in] options Bitmask of options, see @ref nevaloptions.
  * @param[out] node Optional first created node.
  * @return LY_SUCCESS on success.
  * @return LY_EEXIST if the final node to create exists (unless ::LYD_NEW_PATH_UPDATE is used).
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index eb14433..9746faa 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -505,8 +505,8 @@
 
 LY_ERR
 lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
-        size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
-        const struct lysc_node *ctx_node, ly_bool *incomplete)
+        size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
+        uint32_t hints, const struct lysc_node *ctx_node, ly_bool *incomplete)
 {
     LY_ERR ret;
     struct ly_err_item *err = NULL;
@@ -525,6 +525,9 @@
     if (is_utf8) {
         options |= LYPLG_TYPE_STORE_IS_UTF8;
     }
+    if (store_only) {
+        options |= LYPLG_TYPE_STORE_ONLY;
+    }
 
     ret = type->plugin->store(ctx, type, value, value_len, options, format, prefix_data, hints, ctx_node, val, NULL, &err);
     if (dynamic) {
@@ -688,7 +691,7 @@
 
     /* store the value */
     LOG_LOCSET(NULL, &node->node);
-    ret = lyd_value_store(ctx, &val, type, value, value_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
+    ret = lyd_value_store(ctx, &val, type, value, value_len, 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, node->schema, NULL);
     LOG_LOCBACK(0, 1);
     LY_CHECK_RET(ret);
 
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 57ec2c4..2bfa66d 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -225,6 +225,7 @@
  * @param[in] value String value to be parsed.
  * @param[in] value_len Length of @p value, must be set correctly.
  * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable.
+ * @param[in] store_only Whether to perform storing operation only.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] format Input format of @p value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
@@ -236,8 +237,8 @@
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool is_utf8,
-        ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete,
-        struct lyd_node **node);
+        ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
+        ly_bool *incomplete, struct lyd_node **node);
 
 /**
  * @brief Create a term (leaf/leaf-list) node from a parsed value by duplicating it.
@@ -274,12 +275,13 @@
  * @param[in] schema Schema node of the new data node.
  * @param[in] predicates Compiled key list predicates.
  * @param[in] vars Array of defined variables to use in predicates, may be NULL.
+ * @param[in] store_only Whether to perform storing operation only.
  * @param[out] node Created node.
  * @return LY_SUCCESS on success.
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates,
-        const struct lyxp_var *vars, struct lyd_node **node);
+        const struct lyxp_var *vars, ly_bool store_only, struct lyd_node **node);
 
 /**
  * @brief Create a list with all its keys (cannot be used for key-less list).
@@ -289,11 +291,13 @@
  * @param[in] schema Schema node of the new data node.
  * @param[in] keys Key list predicates.
  * @param[in] keys_len Length of @p keys.
+ * @param[in] store_only Whether to perform storing operation only.
  * @param[out] node Created node.
  * @return LY_SUCCESS on success.
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node);
+LY_ERR lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, ly_bool store_only,
+        struct lyd_node **node);
 
 /**
  * @brief Create an anyxml/anydata node.
@@ -464,6 +468,7 @@
  * @param[in] value String value to be parsed.
  * @param[in] value_len Length of @p value, must be set correctly.
  * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable.
+ * @param[in] store_only Whether to perform storing operation only.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] format Input format of @p value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
@@ -476,8 +481,9 @@
  * @return LY_ERR value if an error occurred.
  */
 LY_ERR lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
-        size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format,
-        void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete);
+        size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic,
+        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt,
+        ly_bool *incomplete);
 
 /**
  * @brief Create a copy of the metadata.
@@ -533,6 +539,7 @@
  * @param[in] value Value to be parsed, must not be NULL.
  * @param[in] value_len Length of the give @p value, must be set correctly.
  * @param[in] is_utf8 Whether @p value is a valid UTF-8 string, if applicable.
+ * @param[in] store_only Whether to perform storing operation only.
  * @param[in,out] dynamic Flag if @p value is dynamically allocated, is adjusted when @p value is consumed.
  * @param[in] format Input format of @p value.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
@@ -543,8 +550,8 @@
  * @return LY_ERR value on error.
  */
 LY_ERR lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct lysc_type *type, const void *value,
-        size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints,
-        const struct lysc_node *ctx_node, ly_bool *incomplete);
+        size_t value_len, ly_bool is_utf8, ly_bool store_only, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
+        uint32_t hints, const struct lysc_node *ctx_node, ly_bool *incomplete);
 
 /**
  * @brief Validate previously incompletely stored value.
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index bbe59f2..7a965a3 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -52,8 +52,8 @@
 #include "xpath.h"
 
 LY_ERR
-lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic,
-        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
+lyd_create_term(const struct lysc_node *schema, const char *value, size_t value_len, ly_bool is_utf8, ly_bool store_only,
+        ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, ly_bool *incomplete, struct lyd_node **node)
 {
     LY_ERR ret;
     struct lyd_node_term *term;
@@ -69,7 +69,7 @@
 
     LOG_LOCSET(schema, NULL);
     ret = lyd_value_store(schema->module->ctx, &term->value, ((struct lysc_node_leaf *)term->schema)->type, value,
-            value_len, is_utf8, dynamic, format, prefix_data, hints, schema, incomplete);
+            value_len, is_utf8, store_only, dynamic, format, prefix_data, hints, schema, incomplete);
     LOG_LOCBACK(1, 0);
     LY_CHECK_ERR_RET(ret, free(term), ret);
     lyd_hash(&term->node);
@@ -136,7 +136,7 @@
 
 LY_ERR
 lyd_create_list(const struct lysc_node *schema, const struct ly_path_predicate *predicates, const struct lyxp_var *vars,
-        struct lyd_node **node)
+        ly_bool store_only, struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *list = NULL, *key;
@@ -163,7 +163,7 @@
             /* store the value */
             LOG_LOCSET(predicates[u].key, NULL);
             ret = lyd_value_store(schema->module->ctx, &val, ((struct lysc_node_leaf *)predicates[u].key)->type,
-                    var->value, strlen(var->value), 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, predicates[u].key, NULL);
+                    var->value, strlen(var->value), 0, store_only, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, predicates[u].key, NULL);
             LOG_LOCBACK(1, 0);
             LY_CHECK_GOTO(ret, cleanup);
 
@@ -196,7 +196,7 @@
 }
 
 LY_ERR
-lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, struct lyd_node **node)
+lyd_create_list2(const struct lysc_node *schema, const char *keys, size_t keys_len, ly_bool store_only, struct lyd_node **node)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyxp_expr *expr = NULL;
@@ -214,7 +214,7 @@
             NULL, &predicates), cleanup);
 
     /* create the list node */
-    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, NULL, node), cleanup);
+    LY_CHECK_GOTO(ret = lyd_create_list(schema, predicates, NULL, store_only, node), cleanup);
 
 cleanup:
     LOG_LOCBACK(1, 0);
@@ -471,6 +471,29 @@
     return ret;
 }
 
+/**
+ * @brief Gets format from lyd_new_* options
+ *
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
+ * @param[out] format The output format.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+_lyd_new_val_format(const uint32_t options, LY_VALUE_FORMAT *format)
+{
+    LY_CHECK_ARG_RET(NULL, format, !((options & LYD_NEW_VAL_BIN_VALUE) && (options & LYD_NEW_VAL_CANON_VALUE)), LY_EVALID);
+
+    if (options & LYD_NEW_VAL_BIN_VALUE) {
+        *format = LY_VALUE_LYB;
+    } else if (options & LYD_NEW_VAL_CANON_VALUE) {
+        *format = LY_VALUE_CANON;
+    } else {
+        *format = LY_VALUE_JSON;
+    }
+
+    return LY_SUCCESS;
+}
+
 LIBYANG_API_DEF LY_ERR
 lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
         struct lyd_node **node)
@@ -546,25 +569,25 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Created node.
  * @return LY_ERR value.
  */
 static LY_ERR
 _lyd_new_list_node(const struct ly_ctx *ctx, const struct lyd_node *parent, const struct lys_module *module,
-        const char *name, ly_bool output, struct lyd_node **node)
+        const char *name, uint32_t options, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
     LY_ERR r;
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -583,23 +606,9 @@
     return LY_SUCCESS;
 }
 
-/**
- * @brief Create a new list node in the data tree.
- *
- * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
- * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] format Format of key values.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
- * @param[out] node Optional created node.
- * @param[in] ap Ordered key values of the new list instance, all must be set. For ::LY_VALUE_LYB, every value must
- * be followed by the value length.
- * @return LY_ERR value.
- */
-static LY_ERR
-_lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, LY_VALUE_FORMAT format,
-        ly_bool output, struct lyd_node **node, va_list ap)
+LIBYANG_API_DEF LY_ERR
+lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, uint32_t options,
+        struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *key_s;
@@ -607,13 +616,19 @@
     const void *key_val;
     uint32_t key_len;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
+    va_list ap;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     /* create the list node */
-    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, output, &ret));
+    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, options, &ret));
 
+    va_start(ap, node);
     /* create and insert all the keys */
     for (key_s = lysc_node_child(ret->schema); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
         if (format == LY_VALUE_LYB) {
@@ -623,8 +638,7 @@
             key_val = va_arg(ap, const char *);
             key_len = key_val ? strlen((char *)key_val) : 0;
         }
-
-        rc = lyd_create_term(key_s, key_val, key_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -634,6 +648,7 @@
     }
 
 cleanup:
+    va_end(ap);
     if (rc) {
         lyd_free_tree(ret);
         ret = NULL;
@@ -644,61 +659,21 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_JSON, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_LYB, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, ly_bool output,
-        struct lyd_node **node, ...)
-{
-    LY_ERR rc;
-    va_list ap;
-
-    va_start(ap, node);
-
-    rc = _lyd_new_list(parent, module, name, LY_VALUE_CANON, output, node, ap);
-
-    va_end(ap);
-    return rc;
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, struct lyd_node **node, ...)
+lyd_new_ext_list(const struct lysc_ext_instance *ext, const char *name, uint32_t options, struct lyd_node **node, ...)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *schema, *key_s;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
     va_list ap;
     const char *key_val;
+    size_t key_len;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     schema = lysc_ext_find_node(ext, NULL, name, 0, LYS_LIST, 0);
     if (!schema) {
@@ -717,10 +692,14 @@
 
     /* create and insert all the keys */
     for (key_s = lysc_node_child(schema); key_s && (key_s->flags & LYS_KEY); key_s = key_s->next) {
-        key_val = va_arg(ap, const char *);
-
-        rc = lyd_create_term(key_s, key_val, key_val ? strlen(key_val) : 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
-                NULL, &key);
+        if (format == LY_VALUE_LYB) {
+            key_val = va_arg(ap, const void *);
+            key_len = va_arg(ap, uint32_t);
+        } else {
+            key_val = va_arg(ap, const char *);
+            key_len = key_val ? strlen((char *)key_val) : 0;
+        }
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -737,13 +716,14 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *keys,
-        ly_bool output, struct lyd_node **node)
+        uint32_t options, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -756,7 +736,7 @@
     }
 
     /* find schema node */
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYS_LIST, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name, strlen(name),
                 &schema, &ext);
@@ -769,7 +749,9 @@
         LY_CHECK_RET(lyd_create_inner(schema, &ret));
     } else {
         /* create the list node */
-        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), &ret));
+        ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+
+        LY_CHECK_RET(lyd_create_list2(schema, keys, strlen(keys), store_only, &ret));
     }
     if (ext) {
         ret->flags |= LYD_EXT;
@@ -790,17 +772,15 @@
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
  * @param[in] name Schema node name of the new data node. The node must be #LYS_LIST.
- * @param[in] format Format of key values.
- * @param[in] key_values Ordered key values of the new list instance, all must be set.
- * @param[in] value_lengths Lengths of @p key_values, required for ::LY_VALUE_LYB, optional otherwise.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] key_values Ordered key string values of the new list instance, all must be set.
+ * @param[in] value_lengths Array of lengths of each @p key_values, may be NULL if @p key_values are 0-terminated strings.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 static LY_ERR
-_lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, LY_VALUE_FORMAT format,
-        const void **key_values, uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+_lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, const void **key_values,
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *key_s;
@@ -808,12 +788,16 @@
     const void *key_val;
     uint32_t key_len, i;
     LY_ERR rc = LY_SUCCESS;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, (format != LY_VALUE_LYB) || value_lengths, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     /* create the list node */
-    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, output, &ret));
+    LY_CHECK_RET(_lyd_new_list_node(ctx, parent, module, name, options, &ret));
 
     if (!(ret->schema->flags & LYS_KEYLESS) && !key_values) {
         LOGERR(ctx, LY_EINVAL, "Missing list \"%s\" keys.", LYD_NAME(ret));
@@ -827,7 +811,7 @@
         key_val = key_values[i] ? key_values[i] : "";
         key_len = value_lengths ? value_lengths[i] : strlen(key_val);
 
-        rc = lyd_create_term(key_s, key_val, key_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
+        rc = lyd_create_term(key_s, key_val, key_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &key);
         LY_CHECK_GOTO(rc, cleanup);
         lyd_insert_node(ret, NULL, key, LYD_INSERT_NODE_LAST);
     }
@@ -848,23 +832,21 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const char *name, const char **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_list3(parent, module, name, LY_VALUE_JSON, (const void **)key_values, value_lengths, output, node);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+
+    LY_CHECK_ARG_RET(ctx, !(options & LYD_NEW_VAL_BIN_VALUE), LY_EINVAL);
+
+    return _lyd_new_list3(parent, module, name, (const void **)key_values, value_lengths, options, node);
 }
 
-LIBYANG_API_DEF LY_ERR
+LIBYANG_API_DECL LY_ERR
 lyd_new_list3_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, const void **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
+        uint32_t *value_lengths, uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_list3(parent, module, name, LY_VALUE_LYB, key_values, value_lengths, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_list3_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, const char **key_values,
-        uint32_t *value_lengths, ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_list3(parent, module, name, LY_VALUE_CANON, (const void **)key_values, value_lengths, output, node);
+    options |= LYD_NEW_VAL_BIN_VALUE;
+    return _lyd_new_list3(parent, module, name, key_values, value_lengths, options, node);
 }
 
 /**
@@ -872,33 +854,36 @@
  *
  * @param[in] parent Parent node for the node being created. NULL in case of creating a top level element.
  * @param[in] module Module of the node being created. If NULL, @p parent module will be used.
- * @param[in] name Schema node name of the new data node. The node can be ::LYS_LEAF or ::LYS_LEAFLIST.
- * @param[in] value Value of the node being created.
+ * @param[in] name Schema node name of the new data node. The node can be #LYS_LEAF or #LYS_LEAFLIST.
+ * @param[in] value The value of the node in @p format.
  * @param[in] value_len Length of @p value.
- * @param[in] format Format of @p value.
- * @param[in] output Flag in case the @p parent is RPC/Action. If value is 0, the input's data nodes of the RPC/Action are
- * taken into consideration. Otherwise, the output's data node is going to be created.
+ * @param[in] options Bitmask of options, see @ref newvalueoptions.
  * @param[out] node Optional created node.
  * @return LY_ERR value.
  */
 static LY_ERR
 _lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        size_t value_len, LY_VALUE_FORMAT format, ly_bool output, struct lyd_node **node)
+        size_t value_len, uint32_t options, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_TERM, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -906,7 +891,7 @@
     }
     LY_CHECK_ERR_RET(!schema, LOGERR(ctx, LY_EINVAL, "Term node \"%s\" not found.", name), LY_ENOTFOUND);
 
-    LY_CHECK_RET(lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret));
+    LY_CHECK_RET(lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret));
     if (ext) {
         ret->flags |= LYD_EXT;
     }
@@ -921,35 +906,37 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        ly_bool output, struct lyd_node **node)
+lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *value,
+        uint32_t options, struct lyd_node **node)
 {
-    return _lyd_new_term(parent, module, name, val_str, val_str ? strlen(val_str) : 0, LY_VALUE_JSON, output, node);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+
+    LY_CHECK_ARG_RET(ctx, !(options & LYD_NEW_VAL_BIN_VALUE), LY_EINVAL);
+    return _lyd_new_term(parent, module, name, value, value ? strlen(value) : 0, options, node);
+}
+
+LIBYANG_API_DECL LY_ERR
+lyd_new_term_bin(struct lyd_node *parent, const struct lys_module *module, const char *name,
+        const void *value, size_t value_len, uint32_t options, struct lyd_node **node)
+{
+    options |= LYD_NEW_VAL_BIN_VALUE;
+    return _lyd_new_term(parent, module, name, value, value_len, options, node);
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_term_bin(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        size_t value_len, ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_term(parent, module, name, value, value_len, LY_VALUE_LYB, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_term_canon(struct lyd_node *parent, const struct lys_module *module, const char *name, const char *val_str,
-        ly_bool output, struct lyd_node **node)
-{
-    return _lyd_new_term(parent, module, name, val_str, val_str ? strlen(val_str) : 0, LY_VALUE_CANON, output, node);
-}
-
-LIBYANG_API_DEF LY_ERR
-lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const char *val_str, struct lyd_node **node)
+lyd_new_ext_term(const struct lysc_ext_instance *ext, const char *name, const void *value, size_t value_len,
+        uint32_t options, struct lyd_node **node)
 {
     LY_ERR rc;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
+    LY_VALUE_FORMAT format;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
+    LY_CHECK_RET(_lyd_new_val_format(options, &format));
+    LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
 
     schema = lysc_ext_find_node(ext, NULL, name, 0, LYD_NODE_TERM, 0);
     if (!schema) {
@@ -961,8 +948,7 @@
         }
         return LY_ENOTFOUND;
     }
-    rc = lyd_create_term(schema, val_str, val_str ? strlen(val_str) : 0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA,
-            NULL, &ret);
+    rc = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &ret);
     LY_CHECK_RET(rc);
 
     *node = ret;
@@ -972,13 +958,15 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char *name, const void *value,
-        ly_bool use_value, LYD_ANYDATA_VALUETYPE value_type, ly_bool output, struct lyd_node **node)
+        uint32_t options, LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     LY_ERR r;
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct lysc_ext_instance *ext = NULL;
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
+    uint32_t getnext_opts = (options & LYS_GETNEXT_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
+    ly_bool use_value = (options & LYD_NEW_ANY_USE_VALUE) ? 1 : 0;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name,
             (value_type == LYD_ANYDATA_DATATREE) || (value_type == LYD_ANYDATA_STRING) || value, LY_EINVAL);
@@ -988,7 +976,7 @@
         module = parent->schema->module;
     }
 
-    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, output ? LYS_GETNEXT_OUTPUT : 0);
+    schema = lys_find_child(parent ? parent->schema : NULL, module, name, 0, LYD_NODE_ANY, getnext_opts);
     if (!schema && parent) {
         r = ly_nested_ext_schema(parent, NULL, module->name, strlen(module->name), LY_VALUE_JSON, NULL, name,
                 strlen(name), &schema, &ext);
@@ -1011,12 +999,13 @@
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value, ly_bool use_value,
+lyd_new_ext_any(const struct lysc_ext_instance *ext, const char *name, const void *value, uint32_t options,
         LYD_ANYDATA_VALUETYPE value_type, struct lyd_node **node)
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
     struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
+    ly_bool use_value = (options & LYD_NEW_ANY_USE_VALUE) ? 1 : 0;
 
     LY_CHECK_ARG_RET(ctx, ext, node, name, LY_EINVAL);
 
@@ -1039,10 +1028,12 @@
 
 LIBYANG_API_DEF LY_ERR
 lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys_module *module, const char *name,
-        const char *val_str, ly_bool clear_dflt, struct lyd_meta **meta)
+        const char *val_str, uint32_t options, struct lyd_meta **meta)
 {
     const char *prefix, *tmp;
     size_t pref_len, name_len;
+    ly_bool clear_dflt = options & LYD_NEW_META_CLEAR_DFLT;
+    ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
 
     LY_CHECK_ARG_RET(ctx, ctx || parent, name, module || strchr(name, ':'), parent || meta, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
@@ -1076,15 +1067,16 @@
         val_str = "";
     }
 
-    return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), 0, NULL, LY_VALUE_JSON,
+    return lyd_create_meta(parent, meta, module, name, name_len, val_str, strlen(val_str), 0, store_only, NULL, LY_VALUE_JSON,
             NULL, LYD_HINT_DATA, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
-lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, ly_bool clear_dflt, const struct lyd_attr *attr,
-        struct lyd_meta **meta)
+lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t options, const struct lyd_attr *attr, struct lyd_meta **meta)
 {
     const struct lys_module *mod;
+    ly_bool clear_dflt = options & LYD_NEW_META_CLEAR_DFLT;
+    ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
 
     LY_CHECK_ARG_RET(NULL, ctx, attr, parent || meta, LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
@@ -1118,7 +1110,7 @@
     }
 
     return lyd_create_meta(parent, meta, mod, attr->name.name, strlen(attr->name.name), attr->value, strlen(attr->value),
-            0, NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
+            0, store_only, NULL, attr->format, attr->val_prefix_data, attr->hints, parent ? parent->schema : NULL, clear_dflt, NULL);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -1355,7 +1347,7 @@
 
     /* parse the new value */
     LOG_LOCSET(term->schema, term);
-    ret = lyd_value_store(LYD_CTX(term), &val, type, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA,
+    ret = lyd_value_store(LYD_CTX(term), &val, type, value, value_len, 0, 0, NULL, format, NULL, LYD_HINT_DATA,
             term->schema, NULL);
     LOG_LOCBACK(1, 1);
     LY_CHECK_GOTO(ret, cleanup);
@@ -1445,7 +1437,7 @@
 
     /* parse the new value into a new meta structure */
     ret = lyd_create_meta(NULL, &m2, meta->annotation->module, meta->name, strlen(meta->name), val_str, strlen(val_str),
-            0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
+            0, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, meta->parent ? meta->parent->schema : NULL, 0, NULL);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* compare original and new value */
@@ -1600,7 +1592,7 @@
             if (!r) {
                 /* try to store the value */
                 LY_CHECK_RET(lyd_value_store(schema->module->ctx, &val, ((struct lysc_node_leaflist *)schema)->type,
-                        value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, schema, NULL));
+                        value, value_len, 0, 0, NULL, format, NULL, LYD_HINT_DATA, schema, NULL));
                 ++((struct lysc_type *)val.realtype)->refcount;
 
                 /* store the new predicate so that it is used when searching for this instance */
@@ -1660,12 +1652,13 @@
     struct lyd_node *nparent = NULL, *nnode = NULL, *node = NULL, *cur_parent;
     const struct lysc_node *schema;
     const struct lyd_value *val = NULL;
+    ly_bool store_only = (options & LYD_NEW_VAL_STORE_ONLY) ? 1 : 0;
     LY_ARRAY_COUNT_TYPE path_idx = 0, orig_count = 0;
     LY_VALUE_FORMAT format;
 
     assert(parent || ctx);
     assert(path && ((path[0] == '/') || parent));
-    assert(!(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE));
+    assert(!(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE));
 
     if (!ctx) {
         ctx = LYD_CTX(parent);
@@ -1673,9 +1666,9 @@
     if (value && !value_len) {
         value_len = strlen(value);
     }
-    if (options & LYD_NEW_PATH_BIN_VALUE) {
+    if (options & LYD_NEW_VAL_BIN_VALUE) {
         format = LY_VALUE_LYB;
-    } else if (options & LYD_NEW_PATH_CANON_VALUE) {
+    } else if (options & LYD_NEW_VAL_CANON_VALUE) {
         format = LY_VALUE_CANON;
     } else {
         format = LY_VALUE_JSON;
@@ -1686,7 +1679,7 @@
             LY_PATH_PRED_SIMPLE, &exp), cleanup);
 
     /* compile path */
-    LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, lyd_node_schema(parent), ext, exp, options & LYD_NEW_PATH_OUTPUT ?
+    LY_CHECK_GOTO(ret = ly_path_compile(ctx, NULL, lyd_node_schema(parent), ext, exp, options & LYD_NEW_VAL_OUTPUT ?
             LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p), cleanup);
 
     /* check the compiled path before searching existing nodes, it may be shortened */
@@ -1751,7 +1744,7 @@
                         LYD_NODEHINT_LIST, &node), cleanup);
             } else {
                 /* create standard list instance */
-                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, NULL, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_list(schema, p[path_idx].predicates, NULL, store_only, &node), cleanup);
             }
             break;
         case LYS_CONTAINER:
@@ -1787,8 +1780,7 @@
             if (val) {
                 LY_CHECK_GOTO(ret = lyd_create_term2(schema, val, &node), cleanup);
             } else {
-                LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA,
-                        NULL, &node), cleanup);
+                LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
             }
             break;
         case LYS_LEAF:
@@ -1817,8 +1809,7 @@
             }
 
             /* create a leaf instance */
-            LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, NULL, format, NULL, LYD_HINT_DATA, NULL,
-                    &node), cleanup);
+            LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
             break;
         case LYS_ANYDATA:
         case LYS_ANYXML:
@@ -1876,7 +1867,7 @@
         struct lyd_node **node)
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, NULL, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
@@ -1888,7 +1879,7 @@
         struct lyd_node **new_node)
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, NULL, path, value, value_len, value_type, options, new_parent, new_node);
@@ -1901,7 +1892,7 @@
     const struct ly_ctx *ctx = ext ? ext->module->ctx : NULL;
 
     LY_CHECK_ARG_RET(ctx, ext, path, (path[0] == '/') || parent,
-            !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+            !(options & LYD_NEW_VAL_BIN_VALUE) || !(options & LYD_NEW_VAL_CANON_VALUE), LY_EINVAL);
     LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, ext, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
diff --git a/src/tree_data_sorted.c b/src/tree_data_sorted.c
index 54ad2ff..182e9c5 100644
--- a/src/tree_data_sorted.c
+++ b/src/tree_data_sorted.c
@@ -1170,7 +1170,7 @@
     LY_CHECK_ERR_RET(!modyang, LOGERR(LYD_CTX(leader), LY_EINT, "The yang module is not installed."), LY_EINT);
 
     /* create new metadata, its rbt is NULL */
-    ret = lyd_create_meta(leader, &meta, modyang, RB_NAME, RB_NAME_LEN, NULL, 0, 0, NULL,
+    ret = lyd_create_meta(leader, &meta, modyang, RB_NAME, RB_NAME_LEN, NULL, 0, 0, 1, NULL,
             LY_VALUE_CANON, NULL, LYD_HINT_DATA, NULL, 0, NULL);
     LY_CHECK_RET(ret);
 
diff --git a/src/xpath.c b/src/xpath.c
index bfadbb9..57ba64d 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -6224,7 +6224,7 @@
 
     /* create specific data instance if needed */
     if (scnode->nodetype == LYS_LIST) {
-        LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, NULL, &inst), cleanup);
+        LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, NULL, 1, &inst), cleanup);
     } else if (scnode->nodetype == LYS_LEAFLIST) {
         LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup);
     }