Decode diagnostics

When @boarteam/fix finds a problem it returns it as data — a stable code, a severity, and where in the message it applies. It never throws. This is the complete catalogue: all 82 codes of KnownIssueCode in @boarteam/fix 0.6.1 — the list is generated from the package, the explanations are ours. For how to produce and assert on them in your own code, see the parsing and validation docs.

parse/* — wire decoding

Raised by parse and parseAll while decoding wire bytes: framing, field structure, repeating groups and value coercion. The message still decodes as far as the bytes allow — the damage arrives as data, never an exception.

CodeSeverityWhat it meansUsual cause
parse/empty-inputinfoThe input contained no FIX fields at all.An empty string or buffer, or input that is nothing but separators.
parse/malformed-fieldwarningA segment had no usable tag=value shape; it was reported and dropped.A log line torn mid-field, or non-FIX text mixed into the capture.
parse/missing-begin-stringerrorNo BeginString (8) field was found.A fragment cut before the envelope, or a separator the tokenizer was not told about.
parse/missing-body-lengtherrorNo BodyLength field was found.The message was cut short, or the separator was not what the decoder expected.
parse/missing-msgtypeerrorNo MsgType (35) field was found.Not a FIX message, or only a fragment of one.
parse/framing-ordererrorBeginString, BodyLength and MsgType are present but not in wire positions one, two and three.A hand-assembled message, or fields reordered by whatever produced the log.
parse/begin-string-mismatchwarningBeginString names a different version than the dictionary in use.Decoding a FIX 4.2 message against the FIX 4.4 dictionary, or vice versa.
parse/unknown-msgtypeerrorThe MsgType is not in the dictionary, so the message was parsed flat — fields kept, no group structure.A venue-specific message, or the wrong dialect for the traffic.
parse/missing-checksumerrorNo CheckSum field was found.The message was cut short, or the separator was not what the decoder expected.
parse/checksum-mismatcherrorThe CheckSum field does not match the bytes.Usually a message that was edited, or one copied with pipes after being framed with SOH — the two forms have different checksums.
parse/body-length-mismatchwarningBodyLength disagrees with the framed body.Truncated capture, or a hand-written message where the length was not recomputed.
parse/unknown-taginfoA tag is not defined in the dictionary; the field was kept at the top level.A venue extension the dictionary does not carry — defineExtension teaches it the tag.
parse/tag-not-in-messagewarningThe tag exists in the dictionary but not in this message's definition; kept at the top level.A field borrowed from another message type, or a venue placement the dictionary does not know about.
parse/duplicate-tagerrorThe same tag appeared more than once in one scope; the first value was kept.A repeating group whose counter went missing, flattening entries into duplicates at one level.
parse/duplicate-groupwarningThe same group counter opened twice in one scope; the first group's entries were kept.A message stitched together from fragments, or group entries emitted in two separate runs.
parse/invalid-group-counterrorA group counter's value is not a whole number; it was treated as zero.An empty or corrupted counter value — the parsed entries then also raise a count mismatch.
parse/group-count-mismatchwarningA group counter promised one number of entries and the wire carried another.A truncated message, or entries added or removed without recomputing the counter.
parse/data-length-mismatchReserved in the catalogue; no current code path emits it.Length/data disagreements surface as validate/conditional-required (a data field present without its Length companion) instead.
parse/unknown-datatypewarningA field's declared datatype is not in the dictionary; the value was left as a string.A hand-edited or generated dictionary naming a type it never defines — validateDictionary catches this ahead of time.
parse/invalid-interrorAn int-family field held something that is not a whole number.An empty value, a placeholder like N/A, or a locale-formatted number with a comma.
parse/invalid-floaterrorA float-family field held something that is not a number.Same causes as above.
parse/invalid-booleanerrorA Boolean field held something other than Y or N.true/false or 1/0 from a system that does not speak FIX Booleans.
parse/number-precisionwarningAn integer is lexically valid but exceeds JavaScript's safe range; the exact digits were kept as a string.An identifier packed into an int field with more digits than a double can hold.

validate/* — dictionary conformance

Raised by validate over an already-parsed message: presence of required members, enum membership, value formats, and conditional rules. When validating a FIXT transport/application pair, every issue additionally carries a session or application layer.

CodeSeverityWhat it meansUsual cause
validate/unknown-msgtypewarningThe MsgType is not in the dictionary, so presence and conditional rules were not checked.A venue-specific message, or the wrong dialect — per-field value checks still ran.
validate/required-field-missingerrorA field marked required for this message is absent.A partially-built message, or one built against a different version.
validate/required-group-missingerrorA required repeating group has no entries.Group members supplied at the wrong nesting level are silently dropped when encoding — this is how that shows up.
validate/empty-valueerrorA field is present but its value is empty.A builder that emitted tag= with nothing after it — FIX forbids a tag without a value.
validate/value-not-in-enumerrorAn enumerated field held a value the dictionary does not define.A venue extension, or a value that exists in a different FIX version.
validate/invalid-valueerror / warningA value did not match its datatype's format.Most often a timestamp in ISO format instead of the FIX YYYYMMDD-HH:MM:SS[.sss] form. The ISO country/currency/language checks report as warnings — those sets are heuristics, not dictionary data.
validate/conditional-requirederrorA field required by a condition is absent.Setting PossDupFlag=Y without OrigSendingTime is the classic case; a data field present without its Length companion is the other built-in.
validate/field-outside-layererrorAn application-layer field appeared on a session (admin) message.Only reported when validating a FIXT transport/application pair — business fields do not belong on Logon or Heartbeat traffic.

dict/* — dictionary integrity

Raised by validateDictionary over a DictionaryJSON: the internal consistency of a dictionary before the engine runs on it. The shipped dictionaries pass clean — these appear when loading hand-built, merged or extended ones.

CodeSeverityWhat it meansUsual cause
dict/missing-versionerrorThe dictionary has no version identifier.A hand-built DictionaryJSON missing its top-level version field.
dict/missing-begin-stringerrorThe dictionary has no beginString.Same as above — framing needs the tag 8 value to check against.
dict/missing-datatypeserrorThe datatypes collection is missing or not an object.A truncated or hand-built dictionary; datatype and field-type checks were skipped.
dict/missing-fieldserrorThe fields collection is missing or not an object.Same shape problem; field-level checks were skipped.
dict/missing-componentserrorThe components collection is missing or not an object.Same shape problem; member walks were skipped.
dict/missing-messageserrorThe messages collection is missing or not an array.Same shape problem; message-level checks were skipped.
dict/datatype-cycleerrorA datatype's parent chain loops back on itself.An edit that made a type its own ancestor — the derivation tree must reach a root.
dict/datatype-missing-parenterrorA datatype names a parent that does not exist.A pruned dictionary that dropped a base type but kept its children.
dict/datatype-bad-baseerrorA datatype's base is not one of the five roots: int, float, char, String, data.A typo, or a derived type name written where the root belongs.
dict/field-key-mismatcherrorA field is stored under a key that is not its own tag.Hand-editing the fields record without updating the key it sits under.
dict/field-bad-tagerrorA field's tag is not a positive integer.A zero, negative or non-numeric tag from a generator or edit.
dict/field-unknown-typeerrorA field names a datatype the dictionary does not define.A pruned datatypes table, or a typo in the type name.
dict/duplicate-field-nameerrorTwo tags share one field name.Merging dictionaries or extensions without renaming — name lookups become ambiguous.
dict/duplicate-enum-valuewarningA field lists the same enum value more than once.A merge that concatenated value tables instead of unioning them.
dict/message-missing-msgtypeerrorA message has no MsgType value.A hand-built message entry that never set msgType.
dict/duplicate-msgtypewarningTwo messages claim one MsgType; only the first is reachable.A merge that appended a redefinition instead of replacing the original.
dict/duplicate-message-namewarningTwo messages share one name; lookups by name are ambiguous.Same merge problem as above, on the name side.
dict/unknown-field-referrorA message, component or group body references a field tag that does not exist.A pruned fields table, or a generator emitting references it never defined.
dict/unknown-component-referrorA body references a component that does not exist.Same as above, on the component side — the walk stops at the missing reference.
dict/component-cycleerrorComponent references form a cycle, which can never be expanded.A component that includes itself through intermediaries.
dict/unknown-group-countererrorA repeating group's counter tag is not a defined field.The counter was renumbered or dropped while the group kept pointing at it.
dict/non-counter-group-headwarningA group's counter field exists but is not a NumInGroup type.A plain int heading a group — parse-time counter detection depends on the datatype.
dict/empty-groupwarningA repeating group has no members.An edit that emptied the body; there is nothing for entries to consist of.
dict/unresolvable-group-delimitererrorA group's body resolves to no leading wire field, so entries have no delimiter.A body starting with components that themselves resolve to nothing — the parser could never find entry boundaries.

extend/* — applying extensions

Raised by extendDictionary while applying a venue extension declaration. Severity encodes the outcome: error means the operation was skipped or reverted, warning means it was applied but is worth review (or, for extend/duplicate-member, was already satisfied), info is advisory.

CodeSeverityWhat it meansUsual cause
extend/field-tag-collisionwarningThe extension redefined an existing tag; the extension's definition replaced the base one.A deliberate override, or accidental tag reuse — an identical redefinition is applied silently.
extend/field-name-collisionerrorThe extension field's name is already bound to a different tag; the field was skipped.Pick a unique name, or redefine the existing tag itself.
extend/field-bad-tagerrorThe extension field's tag is not a positive integer; the field was skipped.A typo in the declaration.
extend/field-unknown-typeerrorThe extension field names a datatype the dictionary does not define; the field was skipped.Extensions cannot introduce datatypes — the type must already exist in the base.
extend/tag-outside-user-rangeinfoA new tag lies outside the user-defined ranges (5000–9999 and 20000+).Venues do this in practice — cTrader's 1007/1008, for instance. It may collide with standard tags of other FIX versions; advisory only.
extend/data-length-unwiredwarningA data-typed field was added without a lengthField companion.Without a Length partner, a value that embeds the separator cannot be scanned safely.
extend/enum-unknown-fielderrorEnum values target a field that does not exist; the entry was skipped.A typo, or a field that belongs to a different dialect.
extend/enum-value-conflictwarningAn added enum value already exists on the field under a different name; the extension's entry replaced it.Renaming a stock value — fine when deliberate; an identical value+name pair is deduplicated silently.
extend/component-collisionerrorA new component uses a name that already exists; the definition was skipped.Use the append form to extend the existing component instead of redefining it.
extend/component-cycleerrorThe addition would create a component reference cycle; it was skipped or reverted.A component that ends up including itself through the placement.
extend/msgtype-collisionwarningA new message reuses an existing MsgType; it replaced the original in place.A deliberate message override — MsgType lookup is first-wins, so in-place replacement is the only semantics that works.
extend/message-name-collisionwarningThe new message's name is already used by a message with a different MsgType; both were kept.Name-based lookups — including extension patch targeting — become ambiguous.
extend/header-trailer-injectedinfoThe dictionary's standard header and trailer components were wrapped around the new message's body.Normal and informational: new messages declare only their body.
extend/header-trailer-missingwarningNo standard header or trailer component could be detected; the message was applied without an envelope.A base dictionary without recognisable header/trailer components — encode will silently drop session fields unless the body carries them.
extend/target-not-founderrorA placement's target — component, message, or group path — could not be resolved; the placement was skipped.A typo, an ambiguous message name, or a group that lives behind a shared component: target that component explicitly.
extend/unknown-membererrorA member spec names a field, component or group counter that exists nowhere; the whole placement was skipped.Placements are atomic — one unresolvable name skips the list rather than half-applying it.
extend/member-not-founderrorThe after anchor matches no member of the target body; the placement was skipped.The anchor member was renamed or lives in a different scope than the placement targets.
extend/duplicate-memberwarningThe placed member is already part of the target scope; it was not added again.Re-applying an extension — extendDictionary is idempotent, and this is the expected sign of a double application.
extend/counter-not-markedwarningA placed group's counter field does not derive from NumInGroup.Fix the field's type — parse-time counter detection depends on it.
extend/group-delimiter-shifterrorThe placement would change some repeating group's entry delimiter; everything it inserted was reverted.Inserting ahead of a group's first field — entry detection on real traffic would break.
extend/ambiguous-boundaryerrorThe member could sit where an open repeating group could claim it on re-parse; that member was skipped.Anchor it ahead of the group with after, or place it inside the group instead.
extend/unresolvable-group-delimitererrorA new group's body resolves to no leading wire field; the placement was skipped.The same defect dict/unresolvable-group-delimiter catches, refused before it can enter the dictionary.
extend/data-length-not-placedwarningA data field was placed without its Length companion positioned before it in the same body.Add the Length member ahead of it — encode cannot emit the length, and an embedded separator would corrupt the frame.
extend/counter-as-fieldwarningA NumInGroup counter was placed as a plain scalar member.Use the group form with members instead — on the wire this field heads a repeating group, and real traffic would mis-parse.
extend/invalid-specerrorAn extension entry is structurally malformed; it was skipped.A missing members array or a non-object entry — the issue message names the exact path.
extend/delimiter-definedinfoA group that previously had no resolvable entry delimiter now has one.Usually the fix for dict/unresolvable-group-delimiter landing; advisory.
extend/component-fanoutinfoA component placement is visible in every scope that references the component.Component reuse is the FIX model; the issue lists the affected messages so the fan-out is a known fact, not a surprise.

Severity

Issues carry one of three severities. error means the message is wrong in a way that matters; warning means it is suspect but usable; info is a note. A message can be framed: true and still carry errors — framing only means the envelope was found, not that it checked out, so “framed” is never the same as “valid”. For the extend/* family the severity additionally encodes the outcome of the operation, as the section above describes; parse/data-length-mismatch is declared in the catalogue but currently emitted by no code path, and its row says so rather than inventing behaviour.