Troubleshooting
Common symptoms when integrating @cosyte/terminology, and how to read what the engine is telling
you.
translate returned unmapped - where's my code?
That is the engine working as designed. When a source concept has no target in the supplied map, the
result is a typed unmapped - never a guessed code:
const result = translate(coding, map);
if (result.unmapped) {
result.code; // "TERM_TRANSLATE_UNMAPPED"
result.mode; // "fixed" | "provided" | "other-map" | "none"
result.source; // your original coding, surfaced untouched
}
If the map declares a group.unmapped fallback, its mode (and, for fixed, fixedTarget, or for
other-map, otherMapUrl) is reported on the result - but never silently applied. You decide
whether to trust a fallback.
resolveSystem returned { unknown: true }
The identifier (URI, OID, or mnemonic) is not one the engine recognizes. It returns a typed unknown
rather than guessing a canonical URI. Check the value, and canonicalize known systems by their OID or
HL7 v2 mnemonic (LN, SCT, I10C, …).
loadConceptMap threw
loadConceptMap throws a TerminologyError carrying TERM_CONCEPTMAP_MALFORMED when the resource is
not a usable ConceptMap (wrong resourceType, a target missing its equivalence, and so on). Catch
it and branch on err.code. This is deliberate: a structurally broken map is refused rather than
loaded partially and translating some codes while silently dropping others.
Can I translate a target code back to its source?
Not through a forward map. Steward maps are directional and non-invertible, so translate only
matches the map's source side. Reverse translation needs an explicit inverse ConceptMap.
validateCodeInValueSet returned undetermined - is my code a member or not?
The engine could not prove membership either way, so it refuses to guess. This happens when a part
of the value set cannot be evaluated: an intensional filter/system include whose code system you
did not pass in the ExpansionContext, a referenced value set that is not supplied, an unimplemented
filter operator (regex / generalizes), or a truncated pre-computed expansion. The result
carries code: "TERM_VALUESET_CANNOT_EXPAND" and a diagnostics list naming each gap.
const r = validateCodeInValueSet(coding, valueSet, { codeSystems });
if (r.undetermined) {
r.diagnostics; // each names the code system / value set it could not resolve
}
Supply the missing CodeSystem (or referenced ValueSet) in the context and re-check. A truncated
server expansion must be re-fetched in full - the engine never treats a truncated snapshot as complete
membership (a false "not a member" is a clinical error).
expand returned complete: false
The contains set is a lower bound, not exhaustive membership - some intensional part could not be
computed (see above). Read the diagnostics for which code system or filter was missing; do not
treat the partial contains as the whole value set.
Diagnostics and logs
Diagnostic and error message fields are value-free - they carry a stable code and, at most, a
code + system + version, never a patient identifier. Still, remember that a code in patient
context can be PHI: never log the surrounding record.
Known limitations (this release)
Status:
@cosyte/terminologyships the code-system identity resolver, the ConceptMap$translateengine, the CodeSystem load layer with$lookup/$validate-code, the ValueSetcompose/$expand/ binding operations, UCUM validation, the crosswalk resolvers, and the RxNorm drug graph.
- BYO data -
$expandand binding operate over theCodeSystemreleases and referencedValueSets you supply in theExpansionContext; an intensional part with no supplied code system is a typedTERM_VALUESET_CANNOT_EXPAND, never a fabricated member. - Subsumption is the release's own hierarchy -
is-a/descendent-ofread the loaded code system'sparentedges (nestedconcepts or an explicitparentproperty). Subsumption across two separate releases is not computed. - Intensional filters are best-effort -
is-a/descendent-of/is-not-a/=/in/not-in/existsare implemented;regex/generalizessurface asTERM_VALUESET_CANNOT_EXPAND. - RxNorm graph is BYO -
loadRxNormGraphoperates over the RxNorm RRF release you supply; the engine bundles no RxNorm content. NDC↔RXCUI resolution is release-scoped and carries the as-of release; obsolete/alien NDC statuses come from RxNav NDC-history data (a differential source), not the base RRF concept files, and are never fabricated. Approximate matching is opt-in and always labeled. AnRXCUIwhose supplied atoms could not establish a term type is left out of the graph and reported asTERM_RXNORM_UNTYPED_CONCEPTongraph.warnings, never loaded under a synonym'sTTY; check that list if a concept you expected reads asTERM_RXNORM_UNKNOWN_RXCUI. - No bundled code-system release - every code-system release is bring-your-own, including the content packs (RxNorm Prescribable, ICD-10-CM) and SNOMED CT / CPT / LOINC / UMLS / VSAC.
- What is bundled: the UCUM unit table (
ucum-essence.xmlv2.2, copyright © Regenstrief Institute, Inc., reproduced verbatim under https://ucum.org/license; notice atvendor/ucum/NOTICE.md, which ships with the package), the code-system identity pairings, and the SNOMED CT concepts the crosswalk resolver names - the map-category concepts and the two gender findings (SNOMED CT is copyright © International Health Terminology Standards Development Organisation). So the UCUM operations andresolveSystemwork with no release at all;$lookup,$validate-code,$expand,$translateand the crosswalk and RxNorm resolvers need one you supply.
The API Reference always reflects exactly what this release ships - treat it as the source of truth over any prose above.