skip to content

In a YANG data model, what do the mandatory, min-elements and max-elements statements require of a valid configuration?

level: juniorimportance: should knowfreq 15%

answer

  1. required nodes and entry counts
  2. defaults: false, 0, unbounded
  3. closest ancestor that is not a non-presence container
  4. presence container switches the rule on

basics

~20 s

In YANG, mandatory true makes a leaf or choice required wherever its parent context exists, while min-elements and max-elements bound how many entries a list or leaf-list holds. The server rejects configuration that breaks them.

solid answer

~40 s

`mandatory true` on a `leaf` (or a `choice`, `anydata`, `anyxml`) says the node MUST exist — but only where its closest ancestor that is not a non-presence container exists: in every entry of a list, only while a presence container is there, always at the top level. `min-elements` and `max-elements` bound the number of entries in a `list` or `leaf-list`; they default to `0` and `unbounded`, and `mandatory` defaults to `false`. A leaf cannot carry both `mandatory true` and a `default`, and none of these rules applies while a `when` on the node or an ancestor is false. In a BGP neighbour list, `mandatory true` on `peer-as` makes every neighbour carry a remote AS. A NETCONF server reports a breached count as `operation-failed` with `too-few-elements` or `too-many-elements`.

code

yang · 18 lines
yang
container bgp {
  list neighbor {
    key "address";
    leaf address { type inet:ip-address; }
    leaf peer-as {
      type inet:as-number;
      mandatory true;
    }
    leaf-list address-family {
      type enumeration { enum ipv4-unicast; enum ipv6-unicast; }
      min-elements 1;
    }
    container graceful-restart {
      presence "graceful restart is enabled for this neighbour";
      leaf restart-time { type uint16; mandatory true; }
    }
  }
}

go deeper

for a junior

Recall the three defaults (false, 0, unbounded) and that mandatory applies to leafs and choices while min/max-elements apply to lists and leaf-lists.

for a middle

Explain the placement rule: the closest ancestor that is not a non-presence container decides when a mandatory node must exist, and a false when switches the check off.

for a senior

Show how placement shapes a model: a presence container makes a whole block optional yet internally complete, and a server's count errors name the list, not each entry.

for a principal

Weigh what belongs in the schema: rules every implementation shares go in mandatory and the counts, device limits go in a reported leaf, and later revisions can only relax them.

## What the three statements say A YANG module describes what valid configuration looks like. Most of that is structure — containers, lists, leafs and their types — but structure alone cannot say "this value must be supplied" or "this list needs at least one entry". Three statements defined in RFC 7950 (YANG 1.1) add those rules: - **`mandatory`** takes `true` or `false`, and defaults to `false`. On a `leaf` — and also on a `choice`, `anydata` or `anyxml` node — `mandatory true` means the node MUST exist in valid data, subject to the placement rule below. - **`min-elements`** takes a non-negative integer, defaults to `0`, and applies to a `list` or `leaf-list`: a valid instance has at least that many entries. - **`max-elements`** takes a positive integer or the string `unbounded`, which is the default: a valid list or leaf-list never has more entries than that. RFC 7950 groups the effect under one term, the **mandatory node**: a leaf, choice, anydata or anyxml node with `mandatory true`; a list or leaf-list with `min-elements` above zero; or a container without `presence` that holds at least one mandatory node. ## Where mandatory actually applies "Mandatory" does not mean "present in every configuration". RFC 7950 §7.6.5 ties the rule to the leaf's **closest ancestor in the schema tree that is not a non-presence container** — a non-presence container only groups nodes and carries no meaning of its own, so it is skipped. `min-elements` follows the same rule (§7.7.5). | Closest ancestor, skipping non-presence containers | When the mandatory node must exist | |---|---| | none: the node sits at the top level | always | | a `case` of a `choice` | when any node from that case exists | | a list entry | in every entry of that list | | a presence container | only while that container exists | Take the BGP neighbour model in the code example. `peer-as`, the remote AS, is a direct child of the `neighbor` list, so every neighbour entry must carry it: the server rejects a neighbour configured without a remote AS. `restart-time` is mandatory too, but it lives inside the presence container `graceful-restart`; a neighbour without graceful restart has no such container and needs no restart time. Wrapping `peer-as` in a non-presence container such as `timers` would change nothing, because non-presence containers are skipped when the ancestor is found. ## Counting entries `min-elements 1` on the leaf-list `address-family` requires every neighbour to enable at least one address family. Its closest real ancestor is the list entry, so the count is checked per neighbour, not once across the whole configuration. `max-elements` bounds the other side. Both count entries only; what each entry holds is governed by its own leafs and constraints. ## What switches the checks off 1. **A false `when` or `if-feature`.** RFC 7950 §8.1 enforces `mandatory`, `min-elements` and `max-elements` only while neither the node nor any ancestor has a `when` condition or `if-feature` expression that evaluates to false. A node that does not apply cannot be required. 2. **List keys.** Every key leaf must be given a value when an entry is created, so a `mandatory` statement (and any default) on a key leaf is ignored. 3. **Defaults — which cannot be combined with it.** RFC 7950 says the `default` statement MUST NOT be present on a node where `mandatory` is `true`; a leaf is either required from the client or filled in by the server, never both. ## How a server reports a breach These are validation constraints. A NETCONF server checks them at the end of an `<edit-config>` or `<copy-config>` on the running or startup datastore, and at `<commit>` or `<validate>` when the client works in the candidate datastore. RFC 7950 §15 fixes the replies for the counts: - too many entries: `error-tag` `operation-failed` with `error-app-tag` `too-many-elements`; - too few entries: `error-tag` `operation-failed` with `error-app-tag` `too-few-elements`. Each is returned once, with the error path identifying the list, however many entries are extra or missing. §15 also defines a reply for a missing mandatory `choice` (`data-missing` with `missing-choice`), but none dedicated to a missing mandatory leaf. ## Authoring rules worth knowing - RFC 9907, the YANG authoring guidelines that obsolete RFC 8407, says top-level data definitions MUST NOT be mandatory: such a node makes the datastore invalid the moment the server boots or loads the module. - RFC 9907 also says these statements should express rules that hold for every implementation. A platform limit, such as how many entries one device can hold, belongs in a separate leaf that reports it, not in `max-elements`. - RFC 7950 §11 lets a later revision of a published module remove `mandatory` or change it to `false`, lower `min-elements` or raise `max-elements` — that is, relax a constraint. Tightening one in place is not an allowed revision; it needs a new definition.

  • Why does RFC 9907 say a top-level data definition must not be mandatory?
    A top-level mandatory node has no ancestor that can be absent, so RFC 7950 requires it in every valid datastore. The moment a server boots, or loads the module at runtime, with no such data configured, the datastore is invalid. RFC 9907 therefore forbids it; put the mandatory node under a list entry or a presence container whose existence switches the requirement on.
  • A new revision of a published YANG module raises min-elements on a list from 0 to 1. Is that an allowed revision?
    No. RFC 7950 §11 lets a revision remove `min-elements` or require fewer entries, raise `max-elements`, and drop `mandatory` or set it to `false` — only relaxations. Requiring more could make a configuration that was valid under the old revision invalid under the new one, so the change needs a new definition with a new identifier.

saying these in an interview costs you the question

  • A mandatory leaf has to exist in every configuration, wherever it sits.
  • A mandatory leaf can also carry a default value as a fallback.
  • A YANG list requires at least one entry unless min-elements says 0.
  • mandatory is still enforced on a node whose when condition is false.
  • max-elements is the right place to encode one device's table size.