Optionalsuccess: booleanOptionalmessage: stringOptionaltype: "delete" | "create" | "update"Timestamp when the operation ended
OptionalErrorOptional, a structured error object with additional information
OptionalErrorsOptional, a list of structured error objects with additional information
A message for an end user
Set by a producer whose Message ALREADY renders every entry of Errors, so that
CompleteMessage does not say the same thing twice.
Two kinds of producer build Message out of Errors: the client-side providers, which copy
the SERVER's CompleteMessage (= its errors, joined) into Message and then rehydrate the same
entries into Errors so a form can paint the fields; and the IS-A parent-failure paths, which
write "Failed to save parent entity … : CompleteMessage. A substring dedupe was tried and reverted (it is lossy in ways
a reader cannot detect — see CompleteMessage); a producer stating the fact is exact.
Only honoured when Message actually has text: a producer that set the flag and left Message
empty is contradicting itself, and the errors are still rendered rather than lost.
A copy of the values of the entity object AFTER the operation was performed
A copy of the values of the entity object BEFORE the operation was performed
Timestamp when the operation started
True if successful, false otherwise
The type of operation that was performed
Returns a complete message that includes the Message property (if present), the Error property (if present), and any Errors array items (if present).
StaticErrorRenders ONE entry of the Errors array as human-readable text.
Errors is typed any[], and two shapes land in it from different places:
ValidationErrorInfo — carries Message (capital M), plus Source, Value and
Type. This is what _InnerSave puts there when validation refuses a save: it throws the
ValidationResult, and the catch block assigns newResult.Errors = e.Errors.Error (and anything error-like) — carries lowercase message.This used to read err.message ONLY, so every ValidationErrorInfo fell through to
JSON.stringify(err). That is not a cosmetic difference: CompleteMessage is the string the
server hands the client on a failed save — every write-refusal throw in ResolverBase
(CreateRecord/UpdateRecord/DeleteRecord) puts it in the GraphQLError, and
SaveEntityGraphOperation puts it in ErrorMessage — so the whole point of writing a careful,
field-named refusal in a subclass's ValidateAsync() was defeated at the last step, and the
user saw
{"Source":"ParentContractID","Message":"…","Value":null,"Type":"Failure"} in a toast.
Nothing catches this at compile time because Errors is any[]; nothing catches it at runtime
because JSON.stringify always succeeds. It is only visible by reading the message a user got.
The parameter is unknown rather than any — per .claude/rules/typescript-style.md — because
not knowing the shape is the whole reason this helper exists, and unknown forces the narrowing
that makes each shape's handling explicit. Callers pass any (the Errors array and the Error
property are both legacy any), which is assignable, so no call site changes.
Message is preferred over message because a ValidationErrorInfo has only the former,
while an Error has only the latter — so the order matters solely for an object carrying both,
where the MJ-native field is the better answer.
One entry from the Errors array.
The entry's human-readable text, falling back to JSON for a shape with neither field.
Used for storing the result of a Save or Delete or other transactional operation within a BaseEntity