Skip to content

Result & Issues

After calling Validate or ValidateJSON, you receive a *issue.Result containing all validation issues and statistics.

import "github.com/gofhir/validator/pkg/issue"

Result

type Result struct {
    Issues []Issue
    Stats  *Stats
}

The Result type collects every issue found during validation and provides convenience methods for querying them.

Methods

HasErrors

func (r *Result) HasErrors() bool

Returns true if there is at least one issue with severity error or fatal.

if result.HasErrors() {
    // resource is not valid
}

ErrorCount

func (r *Result) ErrorCount() int

Returns the number of issues with severity error or fatal.

WarningCount

func (r *Result) WarningCount() int

Returns the number of issues with severity warning.

InfoCount

func (r *Result) InfoCount() int

Returns the number of issues with severity information.

Merge

func (r *Result) Merge(other *Result)

Appends all issues from other into this result. Useful when combining results from multiple validation passes.

combined := issue.NewResult()
combined.Merge(resultA)
combined.Merge(resultB)

Filter

func (r *Result) Filter(severity Severity) *Result

Returns a new Result containing only issues that match the given severity.

errorsOnly := result.Filter(issue.SeverityError)
for _, iss := range errorsOnly.Issues {
    fmt.Println(iss.Diagnostics)
}

EnrichLocations

func (r *Result) EnrichLocations(locator func(expression string) *Location)

Adds line and column information to issues based on their FHIRPath expressions. The validator calls this automatically after validation; you typically do not need to call it yourself.


Issue

type Issue struct {
    Severity    Severity
    Code        Code
    Diagnostics string
    Expression  []string
    Location    *Location
    Source      string
    MessageID   string
}

Each Issue corresponds to a single finding from the validation process, aligned with the FHIR OperationOutcome.issue structure.

FieldTypeDescription
SeveritySeveritySeverity level: fatal, error, warning, or information
CodeCodeIssue type code (see Code Constants below)
DiagnosticsstringHuman-readable description of the issue
Expression[]stringFHIRPath expression(s) pointing to the element that caused the issue
Location*LocationLine and column in the source JSON (populated automatically)
SourcestringName of the validation phase that generated the issue
MessageIDstringIdentifier from the error catalog for programmatic handling

Location

type Location struct {
    Line   int
    Column int
}

Represents a position in the source JSON document. Both fields are 1-based. The Location is populated automatically by the validator after all phases complete.


Stats

type Stats struct {
    ResourceType    string
    ResourceSize    int
    ProfileURL      string
    IsCustomProfile bool
    Duration        int64 // nanoseconds
    PhasesRun       int
}

Validation statistics are attached to every Result.

FieldTypeDescription
ResourceTypestringFHIR resource type (e.g. "Patient", "Observation")
ResourceSizeintSize of the input JSON in bytes
ProfileURLstringCanonical URL of the primary profile used for validation
IsCustomProfilebooltrue when a custom profile was used instead of the core resource definition
Durationint64Total validation time in nanoseconds
PhasesRunintNumber of validation phases executed

DurationMs

func (s *Stats) DurationMs() float64

Returns the duration in milliseconds as a floating-point number.

fmt.Printf("Validated in %.2f ms\n", result.Stats.DurationMs())

Severity Constants

Severity levels are aligned with the FHIR IssueSeverity value set.

const (
    SeverityFatal       Severity = "fatal"
    SeverityError       Severity = "error"
    SeverityWarning     Severity = "warning"
    SeverityInformation Severity = "information"
)
ConstantValueMeaning
SeverityFatal"fatal"The issue caused the validation to abort
SeverityError"error"The resource is not valid
SeverityWarning"warning"A potential problem was found but the resource may still be valid
SeverityInformation"information"Informational message, not a problem
When WithStrictMode(true) is set, warnings are promoted to errors. HasErrors() returns true for both error and fatal severities regardless of strict mode.

Code Constants

Code constants are aligned with the FHIR IssueType value set.

const (
    CodeInvalid       Code = "invalid"
    CodeStructure     Code = "structure"
    CodeRequired      Code = "required"
    CodeValue         Code = "value"
    CodeInvariant     Code = "invariant"
    CodeSecurity      Code = "security"
    CodeLogin         Code = "login"
    CodeUnknown       Code = "unknown"
    CodeExpired       Code = "expired"
    CodeForbidden     Code = "forbidden"
    CodeSuppressed    Code = "suppressed"
    CodeProcessing    Code = "processing"
    CodeNotSupported  Code = "not-supported"
    CodeDuplicate     Code = "duplicate"
    CodeMultipleMatch Code = "multiple-matches"
    CodeNotFound      Code = "not-found"
    CodeDeleted       Code = "deleted"
    CodeTooLong       Code = "too-long"
    CodeCodeInvalid   Code = "code-invalid"
    CodeExtension     Code = "extension"
    CodeTooCostly     Code = "too-costly"
    CodeBusinessRule  Code = "business-rule"
    CodeConflict      Code = "conflict"
    CodeTransient     Code = "transient"
    CodeLockError     Code = "lock-error"
    CodeNoStore       Code = "no-store"
    CodeException     Code = "exception"
    CodeTimeout       Code = "timeout"
    CodeIncomplete    Code = "incomplete"
    CodeThrottled     Code = "throttled"
    CodeInformational Code = "informational"
)

The most commonly encountered codes during FHIR validation are:

CodeTypical Use
CodeStructureUnknown elements, invalid JSON structure
CodeRequiredMissing required elements (cardinality min > 0)
CodeValueInvalid primitive values (e.g. malformed date, invalid URI)
CodeInvariantFailed FHIRPath constraint
CodeCodeInvalidCode not found in the bound ValueSet or CodeSystem
CodeExtensionInvalid or unknown extension
CodeNotFoundReferenced profile or resource not found
CodeProcessingGeneral processing errors

Processing Results Programmatically

result, _ := v.Validate(ctx, resource)

// Quick check
if !result.HasErrors() {
    fmt.Println("Resource is valid")
    return
}

// Iterate over all issues
for _, iss := range result.Issues {
    // Build a location string
    loc := ""
    if iss.Location != nil {
        loc = fmt.Sprintf(" (line %d, col %d)", iss.Location.Line, iss.Location.Column)
    }

    // Build an expression string
    expr := ""
    if len(iss.Expression) > 0 {
        expr = fmt.Sprintf(" at %s", iss.Expression[0])
    }

    fmt.Printf("[%s] %s: %s%s%s\n",
        iss.Severity, iss.Code, iss.Diagnostics, expr, loc)
}

// Filter to errors only
errors := result.Filter(issue.SeverityError)
fmt.Printf("\n%d error(s) found\n", len(errors.Issues))

// Access statistics
fmt.Printf("Resource: %s (%d bytes)\n",
    result.Stats.ResourceType, result.Stats.ResourceSize)
fmt.Printf("Profile:  %s\n", result.Stats.ProfileURL)
fmt.Printf("Duration: %.2f ms (%d phases)\n",
    result.Stats.DurationMs(), result.Stats.PhasesRun)
Last updated on