Repository navigation
Description
libyang version: devel at fab861b (project version 6.4.19). The same output is produced by 6.4.13 (f7e0cc1).
libyang 2 and later deliberately create non-presence containers as part of the accessible tree, so this is asked as a question about the intended use of LYD_VALIDATE_PRESENT, not reported as a bug.
Setup
p.yang, a module with a default inside a non-presence container and a mandatory leaf:
module p {
yang-version 1.1;
namespace "urn:example:p";
prefix p;
container np {
leaf t {
type uint8;
default 7;
}
}
leaf m {
type string;
mandatory true;
}
}q.yang, which refers to that default:
module q {
yang-version 1.1;
namespace "urn:example:q";
prefix q;
import p {
prefix p;
}
leaf ref {
type leafref {
path "/p:np/p:t";
}
}
}data.xml contains data of q only:
<ref xmlns="urn:example:q">7</ref>Observations
With LYD_VALIDATE_PRESENT, the defaults of p are not created, so the reference fails:
$ yanglint -e p.yang q.yang data.xml
libyang err : Invalid leafref value "7" - no target instance "/p:np/p:t" with the same value. (/q:ref)
YANGLINT[E]: Failed to parse input data file "data.xml".
Creating the implicit nodes of all modules first makes the reference resolvable, but the implicit container /p:np then makes p count as present, and its mandatory leaf is required:
#include <stdio.h>
#include <libyang/libyang.h>
static struct lyd_node *
parse_with_defaults(struct ly_ctx *ctx)
{
struct lyd_node *tree = NULL;
lyd_parse_data_path(ctx, "data.xml", LYD_XML, LYD_PARSE_ONLY, 0, &tree);
lyd_new_implicit_all(&tree, ctx, LYD_IMPLICIT_NO_STATE, NULL);
return tree;
}
int main(void)
{
struct ly_ctx *ctx;
struct lyd_node *tree;
LY_ERR rc;
ly_ctx_new(ly_yang_module_dir(), 0, &ctx);
ly_ctx_set_searchdir(ctx, ".");
ly_ctx_load_module(ctx, "q", NULL, NULL);
tree = parse_with_defaults(ctx);
rc = lyd_validate_all(&tree, ctx, LYD_VALIDATE_NO_STATE | LYD_VALIDATE_PRESENT, NULL);
printf("lyd_validate_all(LYD_VALIDATE_PRESENT): %d\n", rc);
lyd_free_all(tree);
tree = parse_with_defaults(ctx);
rc = lyd_validate_module(&tree, ly_ctx_get_module_implemented(ctx, "q"), LYD_VALIDATE_NO_STATE, NULL);
printf("lyd_validate_module(q): %d\n", rc);
lyd_free_all(tree);
ly_ctx_destroy(ctx);
return 0;
}$ cc present.c -lyang -o present && ./present
libyang[0]: Mandatory node "m" instance does not exist. (schemadata path: /p:m)
lyd_validate_all(LYD_VALIDATE_PRESENT): 7
lyd_validate_module(q): 0
lyd_data_next_module() counts a module as present when it owns any top-level node, including a node with LYD_DEFAULT set.
Questions
- Is it intended that a module whose only top-level data are implicit nodes (a non-presence container or a default created by
lyd_new_implicit_all()) counts as present forLYD_VALIDATE_PRESENT? The flag is documented as "Validate only modules whose data actually exist", andyanglint -eas "Validate only with the schema modules whose data actually exist in the provided input data files". - If it is intended, is calling
lyd_validate_module()once for each module that owns written top-level data the recommended way to let references see the defaults of other modules (RFC 7950, section 6.4.1: "In the accessible tree, all leafs and leaf-lists with default values in use exist") without enforcing the mandatory nodes of modules that have no data?
Why it matters
A configuration of one module that refers to another module's default currently has to choose between a failed reference (LYD_VALIDATE_PRESENT alone) and constraints of an unrelated module (lyd_new_implicit_all() first).
Related
- ly2: using when causes presence set #1367 (using
whencauses presence to be set), ly2: must stmt causes creation of default nodes to fail #1425 (mustand default node creation), must evaluated in empty container #2140 (mustevaluated in an empty container): the presence of implicit containers is intentional in libyang 2.
Activity
michalvasko commentedon Nov 5, 2026
LYD_VALIDATE_PRESENTis to work with a subset of modules and if you have even implicit data of a module, it means you have worked with it in some way.