Skip to main content

Common errors and troubleshooting

Parse errors

EJsonFlowParseError: Empty JSON string

Cause: TJSONReader.Read('') was called.

Fix: Guard the call:

if LJson <> '' then
LRoot := LReader.Read(LJson);

EJsonFlowParseError: Unexpected end of JSON

Cause: The input JSON is truncated (e.g., only part of a response was received from a network socket).

Fix: Ensure the full response body is accumulated before parsing. For streaming scenarios, use TJSONReader.ReadFromStream with a complete stream.


EJsonFlowParseError: Extra characters after JSON

Cause: Valid JSON followed by trailing characters (e.g., a BOM, whitespace, or a second JSON document concatenated without separation).

Fix: Strip trailing whitespace/BOM from the input before parsing, or split compound streams at document boundaries.


EJsonFlowParseError: Invalid escape sequence

Cause: A \x escape inside a JSON string that is not one of the six valid escapes (\", \\, \/, \b, \f, \n, \r, \t, \uXXXX).

Fix: Ensure the source system produces valid JSON. Use a JSON validator (e.g., jsonlint.com) to identify the bad string.


Serialization errors

Property not appearing in JSON output

Possible causes:

  1. The property is [JSONIgnore] decorated.
  2. The property is private (RTTI does not expose private members by default).
  3. IgnoreNullValues: True in TJSONSerializerOptions and the property value is null/default.

Fix:

  • Make the property public or published.
  • Remove [JSONIgnore] if present.
  • Set IgnoreNullValues := False if null values must be included.

Wrong JSON key name in output

Cause: A [JSONName('key')] attribute is applied to the property, overriding the Delphi property name.

Fix: Check the property declaration for [JSONName] attributes.


Circular reference exception

Cause: An object graph contains a cycle (A → B → A).

Fix: Enable detection in options:

LOptions.DetectCircularReferences := True;
LOptions.CircularReferenceStrategy := crsException; // crsException | crsNull | crsReference | crsIgnore

Schema validation issues

Validation always returns True when no schema is loaded

Cause: ParseSchema was not called before Validate.

Fix:

LValidator.ParseSchema(LSchema); // required before Validate
if not LValidator.Validate(LData) then ...

$ref not resolved — validation skips $ref keywords

Cause: External $ref URIs require a registered IJSONSchemaRef resolver. Without one, external references are skipped or raise an error.

Fix: Register a ref resolver (Indy or Synapse built-ins):

uses
JsonFlow.SchemaRefIndy; // or JsonFlow.SchemaRefSynapse

// The concrete resolver classes (TJSONSchemaRefIndy / TJSONSchemaRefSynapse) implement
// IJSONSchemaRef.FetchReference. No public registration API is exposed on
// TJSONSchemaValidator / IJSONSchemaValidator in the current release — external
// $ref resolution is handled internally by the schema compiler's HTTP resolution
// path (TSchemaCompiler.EnableHTTPResolution). Consult the framework release notes
// for the intended external-ref registration surface.

Brazilian format validators not triggering

Cause: Brazil-specific formats (cpf, cnpj, cep, phone-br, license-plate-br) are in separate units that must be included in the project's search path and explicitly referenced (or their units pulled in).

Fix: Add Source\Schema\Validators\Format\Brazil\ to the project search path and uses one of the Brazil validator units, or call the registry registration code at startup.


Performance issues

Path operations or bulk edits seem slow

Cause: You may be running a JsonFlow version older than the July 2026 performance audit.

Fix: Update to the current version. The audit made parsing up to ~1000× faster on large payloads, path-based editing up to 33× faster (IJSONArray.Insert, reusable internal navigation), and schema validation 3.4× faster — with no opt-in wrappers required. The former TJSONComposerEnhanced/TJSONComposerPool add-ons were removed because the optimized core made them unnecessary.