Skip to content

Say why default construction failed when reading a struct with defaults - #779

Merged
liuzicheng1987 merged 1 commit into
munich-data-engineering:mainfrom
clockblocker:default-construct-error-message
Nov 12, 2026
Merged

liuzicheng1987 merged 1 commit into
munich-data-engineering:mainfrom
clockblocker:default-construct-error-message

Conversation

@clockblocker

@clockblocker clockblocker commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

AI-authored

Explains the failure in #700 in the error message and in the docs. The read still fails.

struct Person {
  rfl::DefaultVal<std::string> name = "Homer Simpson";
  rfl::Validator<std::vector<std::string>, rfl::Size<rfl::Minimum<1>>> favorite_foods;
};

rfl::json::read<Person>(R"({"favorite_foods":["donuts","pizza"]})");
main:        Size validation failed: Value expected to be greater than or equal to 1, but got 0.
this branch: Could not default-construct Person, which is required because it contains rfl::DefaultVal. Give every field a valid default value. Original error: Size validation failed: Value expected to be greater than or equal to 1, but got 0.

For a struct without rfl::DefaultVal that is read with rfl::DefaultIfMissing, the reason reads because it is read with rfl::DefaultIfMissing.

What changes

  • Error text: when T{} throws in read_struct_with_default, the error names the struct, says why it was default-constructed and what to do, and ends with the original message.
  • Docs: a new section "All fields need a valid default value" in docs/content/default_val.md and a note under rfl::DefaultIfMissing in docs/content/processors.md. They show the workaround:
rfl::Validator<std::vector<std::string>, rfl::Size<rfl::Minimum<1>>> favorite_foods =
    std::vector<std::string>({"none"});

The field stays required (Field named 'favorite_foods' not found.). Only with rfl::DefaultIfMissing does the initializer become the value of a missing field.

What does not change

  • No behaviour or API change: every read fails or succeeds as on main. Errors from reading the fields keep their text.
  • Code that compares error().what() with the old text for this case no longer matches.

Tests: tests/json/test_default_construct_error.cpp, 6 tests, 4 of which fail on main. Run locally: 504 of 504 in ctest with Apple clang 17; json 284 of 284 and generic 99 of 99 with GCC 16.2. Not run: Linux, MSVC, older compilers, the other formats.

Related: #778's test expects the bare validator message, so it needs a one-line update when both are merged. #780 builds on this PR and makes the read succeed.

🤖 Generated with Claude Code

A struct that contains rfl::DefaultVal or is read with
rfl::DefaultIfMissing is default-constructed before it is read. If T{}
throws, for instance because a validated field has no valid default
value, the message of the exception was returned as it is:

  Size validation failed: Value expected to be greater than or equal
  to 1, but got 0.

This reads as if the input was wrong, even when the field is in the
input and valid, and it names neither the struct nor the cause.

What is read and what fails stays the same. But the error now names the
struct, says why it was default-constructed and what to do about it,
followed by the original message:

  Could not default-construct Person, which is required because it
  contains rfl::DefaultVal. Give every field a valid default value.
  Original error: Size validation failed: Value expected to be greater
  than or equal to 1, but got 0.

Only a failure of T{} gets this text. An exception thrown later in
read_struct_with_default keeps its own message.

Also document the restriction and the workaround in default_val.md and
processors.md: a field that is given an initializer for this reason
stays required, unless the struct is read with rfl::DefaultIfMissing.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@liuzicheng1987

Copy link
Copy Markdown
Collaborator

@clockblocker thanks for the contribution. I am merging.

@liuzicheng1987
liuzicheng1987 merged commit 1b0a470 into munich-data-engineering:main Nov 12, 2026
176 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants