4  Validation

library(croissant)

validate_croissant(x) checks Croissant metadata and returns every problem found as one CroissantIssues object. x is a Croissant object, or a path, URL, or JSON string, which is read first. The checks follow those of mlcroissant 1.1.1.

4.1 Issues

Each issue has a severity. An error makes the metadata invalid. A warning names an absent recommended property, or a construct that is read in a way the author may not intend.

The following object has five errors: a file without encodingFormat and without a checksum, a source that names a file that does not exist, and a field without a source or data type.

x <- Croissant(
  name = "flawed",
  distribution = list(FileObject(id = "data.csv", content_url = "data.csv")),
  record_set = list(
    RecordSet(
      id = "rs",
      field = list(
        Field(
          id = "rs/a",
          data_type = "sc:Integer",
          source = Source(file_object = "missing.csv", extract = Extract(column = "a"))
        ),
        Field(id = "rs/b")
      )
    )
  )
)
issues <- validate_croissant(x)
issues
<CroissantIssues>
  5 errors, 4 warnings
  Errors
  - [data.csv] The FileObject has no encodingFormat, which is mandatory.
  - [data.csv] The FileObject has neither md5 nor sha256. Add the sha256 checksum of the file at contentUrl.
  - [rs/a] The source names "missing.csv", but no node has that @id. Name the @id of a FileObject, FileSet, RecordSet, or Field of this dataset.
  - [rs/b] The field defines neither source nor value. Add a source that names the file or field its values come from, or a constant value.
  - [rs/b] The field has no dataType, and its source is not a field to take one from. Add a dataType, such as sc:Text or sc:Integer.
  Warnings
  - [Croissant(flawed)] The recommended property citeAs is absent.
  - [Croissant(flawed)] The recommended property datePublished is absent.
  - [Croissant(flawed)] The recommended property license is absent.
  - [Croissant(flawed)] The recommended property version is absent.

print() shows the counts, then the errors, then the warnings. Each line starts with the node: its @id, or its class and name when it has no @id.

is_valid() returns TRUE when the object holds no error. Warnings do not affect it.

is_valid(issues)
[1] FALSE

issues@issues is a data.frame with one row per issue and the character columns severity ("error" or "warning"), check, node, and message. Identical issues appear once.

issues@issues[, c("severity", "check", "node")]
  severity                check              node
1  warning recommended_property Croissant(flawed)
2  warning recommended_property Croissant(flawed)
3  warning recommended_property Croissant(flawed)
4  warning recommended_property Croissant(flawed)
5    error     missing_property          data.csv
6    error     missing_checksum          data.csv
7    error unresolved_reference              rs/a
8    error       missing_source              rs/b
9    error    missing_data_type              rs/b

When x is a document rather than an object, validate_croissant() also reports the problems that read_croissant() raises as an error, such as a value of the wrong JSON type, together with the structural issues. A version error is reported with check version, and any other input error, such as invalid JSON or a missing file, with check input.

doc <- sub('"name": "flawed"', '"name": 42', write_croissant(x))
validate_croissant(doc)
<CroissantIssues>
  6 errors, 4 warnings
  Errors
  - [Croissant] Property name must be text. Received: 42
  - [data.csv] The FileObject has no encodingFormat, which is mandatory.
  - [data.csv] The FileObject has neither md5 nor sha256. Add the sha256 checksum of the file at contentUrl.
  - [rs/a] The source names "missing.csv", but no node has that @id. Name the @id of a FileObject, FileSet, RecordSet, or Field of this dataset.
  - [rs/b] The field defines neither source nor value. Add a source that names the file or field its values come from, or a constant value.
  - [rs/b] The field has no dataType, and its source is not a field to take one from. Add a dataType, such as sc:Text or sc:Integer.
  Warnings
  - [Croissant] The recommended property citeAs is absent.
  - [Croissant] The recommended property datePublished is absent.
  - [Croissant] The recommended property license is absent.
  - [Croissant] The recommended property version is absent.

4.2 Checks

4.2.1 Errors

Check Condition
type A value has the wrong JSON type for its property, or a node is not a JSON object
node_type A node’s @type does not include its class’s type (sc:Dataset, cr:FileObject, cr:FileSet, cr:RecordSet, cr:Field)
duplicate_property Two keys of one node canonicalize to the same property
missing_property A FileObject has no encodingFormat, or no contentUrl when it is not contained in another file; a FileSet has no encodingFormat or includes
missing_checksum A FileObject that is not contained in another file has neither md5 nor sha256, in a dataset without isLiveDataset: true
invalid_id An @id contains whitespace
duplicate_id Two nodes share an @id
unresolved_reference A containedIn, source, or references names an @id that no node has
source_target A source names none, or more than one, of fileObject, fileSet, and field
missing_source A field without subfields, in a record set without inline data, has neither source nor value; or a field has both
missing_data_type A field without subfields has no dataType and its source is not a field; or a field with a constant value has no dataType
undeclared_join The fields of a record set read from two sources and no field joins them with references
inline_data Inline data is an empty array, holds a record that is not an object, or holds a record whose keys are not exactly the field @ids
array_shape arrayShape is given without isArray: true, or has dimensions that are not integers
transform A transform defines no transformation, or more than one of format, jsonPath, regex, replace, and separator
version The document conforms to a Croissant version other than 1.0 or 1.1
input The input cannot be read, for example invalid JSON or a missing file

4.2.2 Warnings

Check Condition
recommended_property The dataset has no citeAs, datePublished, license, or version
missing_property The document has no conformsTo, and is read as Croissant 1.0
missing_id A node has no @id, so no other node can reference it
unresolved_key A record set key names no field, by @id, by @id relative to the record set, or by name
undefined_term A Croissant term is used as a key without a definition in the @context

4.2.3 Differences from mlcroissant

mlcroissant assigns a blank-node @id to a node without one and checks neither record set keys nor JSONPath syntax. croissant reports a missing @id and an unresolved key as warnings and does not parse JSONPath expressions during validation. read_record_set() raises an error of class croissant_jsonpath_error for a JSONPath that it does not evaluate; see Reading records.

The package test suite compares validate_croissant() with mlcroissant 1.1.1 on the 46 example documents and 15 invalid test documents of the MLCommons repository. On the examples, both report no error and the same absent recommended properties. On the invalid documents, the errors reported correspond one to one, with two exceptions that mlcroissant reports and croissant does not: two errors that follow from a whitespace @id, and a second message for one unresolved source.

4.3 A complete record

The metadata below sets every recommended property, the checksum, and the encoding format, and validates without issue.

dir <- tempfile()
dir.create(dir)
writeLines(c("a", "1", "2"), file.path(dir, "data.csv"))

fixed <- Croissant(
  name = "fixed",
  license = "CC0-1.0",
  cite_as = "Fixed data (2026).",
  date_published = "2026-10-27",
  dataset_version = "1.0.0",
  distribution = list(
    FileObject(
      id = "data.csv",
      content_url = "data.csv",
      encoding_format = "text/csv",
      md5 = unname(tools::md5sum(file.path(dir, "data.csv")))
    )
  ),
  record_set = list(
    RecordSet(
      id = "rs",
      field = list(
        Field(
          id = "rs/a",
          data_type = "sc:Integer",
          source = Source(file_object = "data.csv", extract = Extract(column = "a"))
        )
      )
    )
  )
)
validate_croissant(fixed)
<CroissantIssues>
  0 errors, 0 warnings
© 2026 E.D. Gennatas