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:
|
ArgumentOutOfRangeException |
A numeric parameter is outside its valid range — for
example, an EWMA smoothing factor
|
The following snippet shows a pattern for catching and reporting input-validation exceptions before reaching production code:
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 |
|---|---|---|
A stable enum member that uniquely identifies the diagnostic. Use this for programmatic branching rather than parsing the message text. | ||
string | A human-readable explanation of the condition, suitable for display in a UI or log entry. | |
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 |
|---|---|---|
The baseline has fewer than the recommended minimum number of observations. Control limits may not be representative. | ||
One or more rule violations were detected. | ||
The normality test rejected normality. Capability indices
( | ||
Out-of-control signals were detected during assumption diagnostics. | ||
Capability indices were computed but the process shows signs of instability. | ||
Cpm cannot be computed because no target was provided. | ||
The specification is one-sided; some capability indices are not applicable. | ||
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:
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}");
}
}Surfacing Diagnostics to Users
The recommended pattern for surfacing diagnostics in an application UI or API response is:
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."
For severity Info, surface the message in a collapsible "Details" section or tooltip. Info messages do not impair the result.
Include the DiagnosticCodes value in log output to enable downstream filtering and alerting without parsing free-text messages.
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}");
}