Failure Modes

The SPC library distinguishes between two categories of problems: fatal input errors that prevent any meaningful result from being computed (thrown as exceptions), and nonfatal statistical cautions that allow a result to be returned but flag conditions that may affect the trustworthiness of the analysis (surfaced as DiagnosticMessage objects on the result).

This page lists the exceptions thrown for invalid input, describes the diagnostic-message model, and shows how caller code should handle both categories.

Fatal vs. Nonfatal Problems

Category

How signalled

Examples

Fatal — invalid input

Exception thrown; no result is produced.

Null argument, empty vector, NaN observation, negative defect count, mismatched vector lengths.

Nonfatal — statistical caution

DiagnosticMessage attached to the result; analysis completes normally.

Insufficient subgroups for stable limits, possible non-normality of the measurement distribution, process appears unstable when computing capability.

Exceptions from Invalid Input

The following exception types are thrown by SPC methods for invalid caller-supplied arguments:

Exception type

Conditions

ArgumentNullException

A required argument is null: the data vector or matrix, the subgroup-size vector (when required), or a configuration object such as SpecificationLimits.

ArgumentException

Any of the following conditions:

  • Input vector or matrix is empty or has fewer observations than the chart's statistical minimum.

  • Any observation is double.NaN, double.PositiveInfinity, or double.NegativeInfinity.

  • Defect/defective counts are negative, exceed the subgroup size (P/NP charts), or denominators are zero or negative (U charts).

  • A proportion value falls outside [0, 1] in a caller-supplied proportion vector.

  • The subgroup-size vector and the measurement vector have incompatible lengths.

  • A configuration property is logically invalid (e.g., SpecificationLimits with a lower limit exceeding the upper limit).

ArgumentOutOfRangeException

A numeric parameter is outside its valid range — for example, an EWMA smoothing factor λ outside (0, 1], or a CUSUM reference value k that is not strictly positive.

The following snippet shows a pattern for catching and reporting input-validation exceptions before reaching production code:

C#
try
{
    // Empty data: constructor or Analyze() will throw
    double[] tooShort = { };
    IndividualsMovingRangeChartSet chart =
        new IndividualsMovingRangeChartSet(Vector.Create(tooShort));
    chart.Analyze();
}
catch (ArgumentException ex)
{
    Console.WriteLine($"Caught expected exception: {ex.Message}");
}

try
{
    // Non-finite value: check with Diagnose() before calling Analyze()
    double[] hasNaN = { 10.0, double.NaN, 11.0 };
    IndividualsMovingRangeChartSet chart =
        new IndividualsMovingRangeChartSet(Vector.Create(hasNaN));
    DiagnosticReport report = chart.Diagnose();
    if (report.HasErrors)
        Console.WriteLine("Cannot analyze: data contains NaN/Inf.");
}
catch (Exception ex)
{
    Console.WriteLine($"Caught exception: {ex.Message}");
}

The DiagnosticMessage Model

When an analysis completes but the library detects a condition that may limit the trustworthiness of the result, it attaches one or more DiagnosticMessage objects to the result. Each message has three properties:

Property

Type

Description

Code

DiagnosticCodes

A stable enum member that uniquely identifies the diagnostic. Use this for programmatic branching rather than parsing the message text.

Message

string

A human-readable explanation of the condition, suitable for display in a UI or log entry.

Severity

DiagnosticSeverity

Warning (the result should be used with caution or reviewed by a subject matter expert), Info (informational note that does not affect result validity), or Error (a fatal condition that prevented a valid result).

Common Diagnostic Codes

The DiagnosticCodes enum contains all codes the library can produce. The most frequently encountered are:

Code member

Severity

Meaning

ChartBaselineTooFewObservations

Warning

The baseline has fewer than the recommended minimum number of observations. Control limits may not be representative.

RulesViolationsDetected

Warning

One or more rule violations were detected.

AssumptionsNormalityRejected

Warning

The normality test rejected normality. Capability indices (Cp, Cpk, etc.) may be inaccurate.

AssumptionsProcessUnstable

Warning

Out-of-control signals were detected during assumption diagnostics.

CapabilityProcessMayBeUnstable

Warning

Capability indices were computed but the process shows signs of instability.

CapabilityTargetNotSpecified

Info

Cpm cannot be computed because no target was provided.

CapabilityOneSidedSpecification

Info

The specification is one-sided; some capability indices are not applicable.

ChartInputNonFiniteValues

Warning

Input data contains NaN or infinite values.

Checking for Diagnostics

After every analysis call, inspect the HasMessages property on the returned ControlChart before using the result:

C#
double[] data = {
    10.5, 11.2, 10.8, 11.5, 10.3, 11.8, 10.1, 11.4,
    10.9, 11.1, 10.6, 11.3, 10.7, 11.0, 10.4
};
IndividualsMovingRangeChartSet chart =
    new IndividualsMovingRangeChartSet(Vector.Create(data));

// Run pre-flight diagnostics (before Analyze)
DiagnosticReport report = chart.Diagnose();
if (report.HasMessages)
{
    Console.WriteLine("Diagnostics:");
    foreach (DiagnosticMessage msg in report.Messages)
    {
        Console.WriteLine(
            $"  [{msg.Severity}] {msg.Code}: {msg.Message}");
    }
}

  Note

HasMessages is false when the diagnostics collection is empty. It is always safe to skip the check and proceed directly to the result, but surfacing warnings to the end user leads to more reliable process decisions.

Surfacing Diagnostics to Users

The recommended pattern for surfacing diagnostics in an application UI or API response is:

  1. For each diagnostic with severity Warning, render a visible warning banner or badge on the chart — for example, "⚠ Control limits may be unreliable: fewer than 25 subgroups were used."

  2. For severity Info, surface the message in a collapsible "Details" section or tooltip. Info messages do not impair the result.

  3. Include the DiagnosticCodes value in log output to enable downstream filtering and alerting without parsing free-text messages.

C#
double[] data = {
    10.5, 11.2, 10.8, 11.5, 10.3, 11.8, 10.1, 11.4,
    10.9, 11.1, 10.6, 11.3, 10.7, 11.0, 10.4
};
IndividualsMovingRangeChartSet chart =
    new IndividualsMovingRangeChartSet(Vector.Create(data));
DiagnosticReport report = chart.Diagnose();

// Filter for warnings only and surface them
foreach (DiagnosticMessage msg in report.Messages)
{
    if (msg.Severity == DiagnosticSeverity.Warning)
        Console.WriteLine($"Warning: {msg.Message}");
}

See Also