Parameter Schemas for Validation and Surprise Checking

The schema validator supports a focused subset of JSON Schema , along with a few Conduit-specific extensions under constraints.

Defined in:

  • src/libs/flow/flow_schema_validator.hpp

  • src/libs/flow/flow_schema_validator.cpp

The validator is designed to validate Conduit nodes against a schema expressed as another Conduit node.

Note

When writing schemas for this validator, assume:

  • only the fields documented here are supported

  • unsupported JSON Schema keywords are ignored unless explicitly handled by the validator

  • several behaviors differ from standard JSON Schema because they are adapted to Conduit’s data model

API Surface

The public API is:

  • bool flow::schema::validate(const conduit::Node &schema, const conduit::Node &input, conduit::Node &info);

  • void flow::schema::set_expression_checker(ExpressionCheckFn fn);

validate returns true on success. On failure, info["errors"] is populated with one or more human-readable error strings.

Quick Usage Pattern

A schema is itself a Conduit node that describes the expected structure of an input node.

A typical object schema looks like this:

{
  "type": "object",
  "required": ["name"],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1
    },
    "count": {
      "type": "integer"
    }
  },
  "additionalProperties": false
}

In pseudocode, validation looks like:

conduit::Node schema; // schema definition
conduit::Node input;  // node to validate
conduit::Node info;   // receives errors
const bool ok = flow::schema::validate(schema, input, info);

If ok is false, read info["errors"] (a list of strings) for details.

Supported Keywords

type

The validator uses schema["type"] (a string) to decide which validations to apply. Supported types are:

  • object: A conduit object node

  • string: A string leaf node

  • number: Any numeric type

  • integer: Any integer type

  • array: a Conduit list, a Conduit object, or a numeric leaf array (a numeric node with number_of_elements() >= 1).

Note

Empty input nodes (dtype().is_empty()) are treated specially:

  • If the schema type is "object" and the input is empty, the validator validates as if the input were an empty Conduit object.

  • If the schema type is "array" and the input is empty, the validator validates as if the input were an empty Conduit list.

Warning

Unknown type values are reported as schema errors.

Example:

# Schema: non-empty string
type: string
minLength: 1
Validation Failure Example (type mismatch)
# Schema
type: string

# Input
42
Validation failed at '<root>' (type): type mismatch. Expected type 'string'.

format

Format checking is an additional layer of string validation that allows for the input strings to be validated against a given format. Formats can be registered with the schema validator using register_format_checker(const std::string &format_name, bool (*)(const std::string &expr, std::string &err_msg) callback). Once a format is registered, it can be refrenced in the schemas using the format name they were registered with.

Example:

If you had the following function to check if a string matches a specific expression grammar:

bool is_valid_expression(const std::string &expr, std::string &err_msg)
{
    bool res = true;
    try
    {
        scan_string(expr.c_str());
    }
    catch(const char *msg)
    {
        err_msg = msg;
        res = false;
    }
    return res;
}

You could register it with the schema validator:

flow::schema::register_format_checker("expression", &is_valid_expression);

and then use it in any schemas to validate strings:

type: string
format: expression

enum

Restricts a string input to one of the allowed values.

  • The validator only applies enum when the input value is a string.

  • The allowed list is expected to be a list of strings in the schema.

Example:

type: string
enum: ["nearest", "linear"]
Validation Failure Example (enum mismatch)
# Schema
type: string
enum: ["nearest", "linear"]

# Input
"furthest"
Validation failed at '<root>' (enum): 'furthest' is not one of the allowed enum entries. Expected one of {nearest, linear}.

allOf

Requires that the input validates against all subschemas in the array.

On failure, the validator records a summary message and may add a small number of per-option “hint” messages derived from the first error in each failing option.

Example:

# Require multiple constraints at once.
allOf:
  - {type: string, minLength: 1}
  - {type: string, pattern: "^[a-z0-9_]+$"}
Validation Failure Example (string not matching all schemas)
# Schema
allOf:
  - {type: string, minLength: 1}
  - {type: string, enum: ["nearest", "linear"]}

# Input
"furthest"
Validation failed at '<root>' (all of): expected all of the 2 schema options to match, but only one matched
    Option 0 hint: Validation failed at '<root>' (enum): 'furthest' is not one of the allowed enum entries. Expected one of {nearest, linear}.

oneOf

Requires that the input validates against exactly one subschema in the array.

On failure, the validator records a summary message and may add a small number of per-option “hint” messages derived from the first error in each failing option.

Example:

# Accept exactly one option; keep ranges non-overlapping to avoid ambiguity.
oneOf:
  - {type: integer, maximum: 9}
  - {type: integer, minimum: 10}
Validation Failure Example (no matching option; note the per-option hints)
# Schema
oneOf:
  - {type: integer, maximum: 5}
  - {type: integer, minimum: 10}

# Input
8
Validation failed at '<root>' (one of): expected exactly one of 2 schema options to match, but none matched.
    Option 0 hint: Validation failed at '<root>' (maximum): 8 is above the allowed maximum. Expected number <= 5.
    Option 1 hint: Validation failed at '<root>' (minimum): 8 is below the allowed minimum. Expected number >= 10.

anyOf

Requires that the input validates against at least one subschema in the array.

On failure, the validator records a summary message and may add a small number of per-option “hint” messages derived from the first error in each failing option.

Example:

# Accept either a string name or an integer id.
anyOf:
  - {type: string, minLength: 1}
  - {type: integer, minimum: 0}
Validation Failure Example (no matching option; note the per-option hints)
# Schema
anyOf:
  - {type: integer, maximum: 5}
  - {type: integer, minimum: 10}

# Input
8
Validation failed at '<root>' (any of): input did not match any allowed schema option. Expected at least one schema option to match.
    Option 0 hint: Validation failed at '<root>' (maximum): 8 is above the allowed maximum. Expected number <= 5.
    Option 1 hint: Validation failed at '<root>' (minimum): 8 is below the allowed minimum. Expected number >= 10.

String Keywords (type: "string")

minLength

Requires the string length to be at least this integer value.

Example:

type: string
minLength: 3
Validation Failure Example
# Input
"ab"
Validation failed at '<root>' (minLength): string is too short. Length is 2. Expected string length >= 3.

maxLength

Requires the string length to be at most this integer value.

Example:

type: string
maxLength: 8

pattern

Requires the string to match the regular expression pattern.

Note

  • The validator uses C++ std::regex and checks with std::regex_search (i.e., the pattern may match any substring; it is not implicitly anchored). To require a full-string match, add anchors (e.g., ^...$).

  • Invalid regex patterns are reported as schema errors.

Example:

type: string
pattern: "^[a-z]+$"
Validation Failure Example (pattern mismatch)
# Shema
type: string
pattern: "^A+$"

# Input
"Abc"
Validation failed at '<root>' (pattern): string does not match required pattern '^A+$'.
Validation Failure Example (schema error from invalid regex)
# Schema
type: string
pattern: "["

# Input
"anything"
Schema error near '<root>' (pattern): invalid regex pattern '['.

Numeric Keywords (type: "number" / type: "integer")

minimum

Requires the numeric value to be >= minimum.

Example:

type: number
minimum: 0.0
Validation Failure Example
# Input
-1.0
Validation failed at '<root>' (minimum): -1.000000 is below the allowed minimum. Expected number >= 0.

exclusiveMinimum

Requires the numeric value to be > exclusiveMinimum.

Example:

type: number
exclusiveMinimum: 0.0

maximum

Requires the numeric value to be <= maximum.

Example:

type: number
maximum: 1.0

exclusiveMaximum

Requires the numeric value to be < exclusiveMaximum.

Example:

type: number
exclusiveMaximum: 1.0

Object Keywords (type: "object")

properties

Declares named subschemas for object children.

The validator only validates properties that are present in the input. Missing properties are not an error unless required by required.

Example (used below with required and additionalProperties):

type: object
additionalProperties: false
properties:
  name: {type: string, minLength: 1}
  count: {type: integer, minimum: 0}
required: [name, count]

required

A list of string field names that must be present on the input object.

Example:

type: object
properties:
  name: {type: string}
required: [name]

additionalProperties

If present and falsey (to_int() == 0), forbids any input object children not declared in properties. This is equivalent to enforcing “surprise checking” against the schema.

If the keyword is not present, additional properties are allowed.

Example:

type: object
additionalProperties: false
properties:
  name: {type: string}
Validation Failure Example
# Input
name: "ok"
debug: "nope"
Validation failed at 'debug' (additionalProperties): unexpected additional field is not allowed here.

Array Keywords (type: "array")

minItems

Requires the array length to be at least this integer value.

Example:

type: array
minItems: 1

maxItems

Requires the array length to be at most this integer value.

Example:

type: array
maxItems: 3

items

A subschema applied to each element of the input.

Notes:

  • For Conduit lists and objects, elements are accessed via child(i).

  • For Conduit numeric leaf arrays, each element is validated by aliasing the i’th element as an external scalar node and applying the items schema.

Example:

type: array
minItems: 1
maxItems: 3
items: {type: integer, minimum: 0}

Non-Standard Keywords (constraints/*)

The validator supports several extra keywords under a constraints object. These are not standard JSON Schema keywords, but they allow for more flexible and explicit validation schemas.

constraints/skip

If present and truthy (to_int() != 0), validation for that schema node is skipped entirely (it always succeeds).

Example:

type: object
constraints:
  skip: true

Note

This additional feature allows for schemas to be defined without being explicitly validated against or surprise checked. This allows for subsets of a schema to be validated while the remainder of the schema can be ignored or validated at a later time.

constraints/forbid

For object inputs only. A list of string field names that must not be present.

Example:

type: object
constraints:
  forbid: ["debug", "internal_only"]

Note

Standard JSON Schema can express “forbidden properties”, but it is verbose (typically involving nested not + required combinations). This keyword is a compact way to enforce deprecations, feature gating, or to block internal knobs from user-facing schemas while keeping the rest of the object open to evolution.

constraints/const

Requires the input to exactly match a constant value.

Supported constant types in the schema are:

  • string

  • integer

  • number

Unsupported constant types are reported as schema errors.

Example:

# Require a fixed string "v1"
constraints: {const: "v1"}

Note

Standard JSON Schema has a top-level const keyword, but this validator nests some non-standard rules under constraints. Keeping const here allows schemas to group “extra constraints” together and keeps the validator’s behavior explicit and easy to scan in Conduit/YAML.

constraints/not_const

For object inputs only. Forbids specific constant values for specific fields.

The schema value is expected to be an object whose children are field names, where each field maps to a forbidden constant value (string, integer, or number). If the input contains that field with the same value, validation fails.

Example:

type: object
constraints:
  not_const:
    mode: "unsafe"
    retries: 0

Note

This is a concise way to ban specific values (e.g., mode: "unsafe" or retries: 0) without rewriting the entire field schema or adding complex boolean logic. In standard JSON Schema this typically requires multiple not clauses that can be harder to read and maintain.

constraints/dependencies

For object inputs only. Declares field dependencies.

The schema value is expected to be an object mapping a trigger field name to a list of required field names. If the trigger field is present in the input, all required fields must also be present.

Example:

type: object
constraints:
  dependencies:
    output_path: ["output_protocol"]

Note

JSON Schema dependency tracking varries between versions of JSON schema. This validator elected to match the language used in Draft 7. Similarly to constraints/const, standard JSON Schema generally has dependencies at the tope level, but this validator elects to store them under constraints. Keeping const here allows schemas to group “extra constraints” together and keeps the validator’s behavior explicit and easy to scan in Conduit/YAML.

constraints/exclusiveChildren

For object inputs only. Declares a list of mutually-exclusive field names.

By default, the validator allows zero or one of the listed fields to be present. If more than one is present, validation fails.

Example:

type: object
constraints:
  exclusiveChildren: ["file", "buffer"]

Note

Mutually-exclusive property groups are common in parameter schemas (“choose one of these ways to specify the input”). Standard JSON Schema can encode this with oneOf and multiple required/not combinations, but the result is verbose and difficult to maintain as the option set grows. This keyword provides a consise and simple approach to this functionality.

constraints/allowNoneInExclusiveGroup

Only used with constraints/exclusiveChildren.

If present and falsey (to_int() == 0), the validator requires exactly one of the mutually-exclusive fields to be present (it becomes an error if none are present).

Example (require exactly one instead of zero-or-one):

type: object
constraints:
  exclusiveChildren: ["file", "buffer"]
  allowNoneInExclusiveGroup: false

Note

Many schemas want “exactly one” while others want “zero or one” (optional selection). This keyword extends the constraints/exclusiveChildren keyword and allows schemas to toggle between the two behaviors.