Skip to content

Errors

The MPL SDK defines a structured error hierarchy for different failure modes. All errors extend MplError and include an error code, message, and JSON serialization for wire transport.


Import

import {
  MplError,
  SchemaFidelityError,
  QomBreachError,
  NegotiationError,
  UnknownStypeError,
  ConnectionError,
  HashMismatchError,
  PolicyDeniedError,
} from '@mpl/sdk';

Error Hierarchy

Error (built-in)
└── MplError
    ├── SchemaFidelityError
    ├── QomBreachError
    ├── UnknownStypeError
    ├── NegotiationError
    ├── ConnectionError
    ├── HashMismatchError
    └── PolicyDeniedError

Error Codes

Every MplError carries a string code for programmatic handling:

Code Error Class Description
E-SCHEMA-FIDELITY SchemaFidelityError Payload does not match the SType schema
E-QOM-BREACH QomBreachError QoM profile thresholds not met
E-UNKNOWN-STYPE UnknownStypeError SType not found in registry
E-NEGOTIATION-FAILED NegotiationError AI-ALPN handshake rejected
E-CONNECTION ConnectionError WebSocket or HTTP connection failed
E-HASH-MISMATCH HashMismatchError Semantic hash verification failed
E-POLICY-DENIED PolicyDeniedError Policy engine denied the operation

MplError

Base class for all MPL errors. Extends the built-in Error with a structured code and JSON serialization.

class MplError extends Error {
  readonly code: string;

  constructor(code: string, message: string);
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string Machine-readable error code
message string Human-readable error description (inherited from Error)
name string Always "MplError"

toJSON()

Serialize the error for wire transport or logging.

toJSON(): Record<string, unknown>

Returns:

{
  "error": "E-SCHEMA-FIDELITY",
  "message": "Payload does not match schema for org.calendar.Event.v1"
}

Example

try {
  await client.call('calendar.create', { title: 123 });
} catch (error) {
  if (error instanceof MplError) {
    console.error('Code:', error.code);
    console.error('Message:', error.message);
    console.error('JSON:', JSON.stringify(error.toJSON()));
  }
}

SchemaFidelityError

Thrown when a payload fails JSON Schema validation against its declared SType.

class SchemaFidelityError extends MplError {
  readonly stype: string;
  readonly validationErrors: Array<{ path: string; message: string }>;

  constructor(
    stype: string,
    validationErrors: Array<{ path: string; message: string }>,
  );
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-SCHEMA-FIDELITY"
stype string The SType that the payload failed to match
validationErrors Array<{ path: string; message: string }> Detailed validation failures

toJSON() Output

{
  "error": "E-SCHEMA-FIDELITY",
  "message": "Payload does not match schema for org.calendar.Event.v1",
  "stype": "org.calendar.Event.v1",
  "validation_errors": [
    { "path": "/title", "message": "must be string" },
    { "path": "/start", "message": "must match format \"date-time\"" }
  ]
}

Example

import { SchemaFidelityError } from '@mpl/sdk';

try {
  await session.send('org.calendar.Event.v1', {
    title: 123,           // Should be string
    start: 'not-a-date',  // Should be date-time format
  });
} catch (error) {
  if (error instanceof SchemaFidelityError) {
    console.error(`Schema mismatch for ${error.stype}:`);
    for (const ve of error.validationErrors) {
      console.error(`  ${ve.path}: ${ve.message}`);
    }
    // "Schema mismatch for org.calendar.Event.v1:"
    // "  /title: must be string"
    // "  /start: must match format "date-time""
  }
}

QomBreachError

Thrown when QoM metrics do not meet the required profile thresholds.

class QomBreachError extends MplError {
  readonly profile: string;
  readonly metrics: Record<string, number>;
  readonly failures: Array<{ metric: string; actual: number; threshold: number }>;

  constructor(
    profile: string,
    metrics: Record<string, number>,
    failures: Array<{ metric: string; actual: number; threshold: number }>,
  );
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-QOM-BREACH"
profile string Name of the profile that was not met
metrics Record<string, number> All measured metrics
failures Array<...> Metrics that fell below their thresholds

toJSON() Output

{
  "error": "E-QOM-BREACH",
  "message": "QoM profile qom-strict-argcheck not met: instructionCompliance",
  "profile": "qom-strict-argcheck",
  "metrics": {
    "schemaFidelity": 1.0,
    "instructionCompliance": 0.72
  },
  "failures": [
    { "metric": "instructionCompliance", "actual": 0.72, "threshold": 0.95 }
  ]
}

Example

import { QomBreachError } from '@mpl/sdk';

try {
  const response = await processWithQom(payload);
} catch (error) {
  if (error instanceof QomBreachError) {
    console.error(`Profile "${error.profile}" not met`);
    for (const f of error.failures) {
      console.error(
        `  ${f.metric}: got ${f.actual}, needed >= ${f.threshold}`
      );
    }
  }
}

NegotiationError

Thrown when the AI-ALPN handshake fails because client and server cannot agree on capabilities.

class NegotiationError extends MplError {
  readonly clientStypes: string[];
  readonly serverStypes: string[];
  readonly reason?: string;

  constructor(
    clientStypes: string[],
    serverStypes: string[],
    reason?: string,
  );
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-NEGOTIATION-FAILED"
clientStypes string[] STypes offered by the client
serverStypes string[] STypes supported by the server
reason string \| undefined Server-provided reason for rejection

toJSON() Output

{
  "error": "E-NEGOTIATION-FAILED",
  "message": "No common STypes between client and server",
  "client_stypes": ["org.calendar.Event.v1", "org.calendar.Invite.v1"],
  "server_stypes": ["org.finance.Transaction.v1"]
}

Example

import { NegotiationError } from '@mpl/sdk';

try {
  await session.connect();
} catch (error) {
  if (error instanceof NegotiationError) {
    console.error('Negotiation failed:', error.reason);
    console.error('We offered:', error.clientStypes);
    console.error('Server supports:', error.serverStypes);

    // Find what's missing
    const missing = error.clientStypes.filter(
      s => !error.serverStypes.includes(s)
    );
    console.error('Server missing:', missing);
  }
}

UnknownStypeError

Thrown when an SType is referenced that does not exist in the registry.

class UnknownStypeError extends MplError {
  readonly stype: string;

  constructor(stype: string);
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-UNKNOWN-STYPE"
stype string The unrecognized SType identifier

toJSON() Output

{
  "error": "E-UNKNOWN-STYPE",
  "message": "Unknown SType: org.calendar.Event.v99",
  "stype": "org.calendar.Event.v99"
}

Example

import { UnknownStypeError } from '@mpl/sdk';

try {
  await client.send('org.calendar.Event.v99', payload);
} catch (error) {
  if (error instanceof UnknownStypeError) {
    console.error(`SType not found: ${error.stype}`);
    console.error('Check the registry or version number');
  }
}

ConnectionError

Thrown when a WebSocket or HTTP connection cannot be established.

class ConnectionError extends MplError {
  readonly endpoint: string;
  readonly cause?: string;

  constructor(endpoint: string, cause?: string);
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-CONNECTION"
endpoint string The URL that failed to connect
cause string \| undefined Underlying error message

toJSON() Output

{
  "error": "E-CONNECTION",
  "message": "Failed to connect to ws://localhost:9443/ws",
  "endpoint": "ws://localhost:9443/ws",
  "cause": "ECONNREFUSED"
}

Example

import { ConnectionError } from '@mpl/sdk';

try {
  await session.connect();
} catch (error) {
  if (error instanceof ConnectionError) {
    console.error(`Cannot reach ${error.endpoint}`);
    if (error.cause) {
      console.error(`Reason: ${error.cause}`);
    }
    // Implement retry logic
    await retryWithBackoff(() => session.connect());
  }
}

HashMismatchError

Thrown when verifying a semantic hash and the computed hash does not match the expected value.

class HashMismatchError extends MplError {
  readonly expected: string;
  readonly actual: string;

  constructor(expected: string, actual: string);
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-HASH-MISMATCH"
expected string The hash that was expected
actual string The hash that was computed

toJSON() Output

{
  "error": "E-HASH-MISMATCH",
  "message": "Semantic hash mismatch",
  "expected": "b3:a1b2c3d4e5f6...",
  "actual": "b3:f6e5d4c3b2a1..."
}

Example

import { HashMismatchError, verifyHash } from '@mpl/sdk';

function verifyEnvelopeIntegrity(envelope: MplEnvelope): void {
  if (envelope.semHash) {
    const isValid = verifyHash(envelope.payload, envelope.semHash);
    if (!isValid) {
      throw new HashMismatchError(
        envelope.semHash,
        semanticHash(envelope.payload),
      );
    }
  }
}

try {
  verifyEnvelopeIntegrity(receivedEnvelope);
} catch (error) {
  if (error instanceof HashMismatchError) {
    console.error('Payload was tampered with!');
    console.error(`Expected: ${error.expected}`);
    console.error(`Got: ${error.actual}`);
  }
}

PolicyDeniedError

Thrown when the policy engine denies an operation.

class PolicyDeniedError extends MplError {
  readonly policy: string;
  readonly reason: string;
  readonly remediation?: string;

  constructor(policy: string, reason: string, remediation?: string);
  toJSON(): Record<string, unknown>;
}
Property Type Description
code string "E-POLICY-DENIED"
policy string Name of the policy that blocked the operation
reason string Why the policy was triggered
remediation string \| undefined Suggested action to resolve the issue

toJSON() Output

{
  "error": "E-POLICY-DENIED",
  "message": "Policy data-residency denied: Payload contains PII routed to non-EU region",
  "policy": "data-residency",
  "reason": "Payload contains PII routed to non-EU region",
  "remediation": "Use eu-west-1 endpoint for PII-containing payloads"
}

Example

import { PolicyDeniedError } from '@mpl/sdk';

try {
  await client.send('org.medical.Diagnosis.v1', sensitivePayload);
} catch (error) {
  if (error instanceof PolicyDeniedError) {
    console.error(`Policy "${error.policy}" denied this request`);
    console.error(`Reason: ${error.reason}`);
    if (error.remediation) {
      console.log(`Fix: ${error.remediation}`);
    }
  }
}

Error Handling Patterns

Comprehensive Error Handling

import {
  MplError,
  SchemaFidelityError,
  QomBreachError,
  NegotiationError,
  ConnectionError,
  HashMismatchError,
  PolicyDeniedError,
} from '@mpl/sdk';

async function robustCall(session: Session, stype: string, payload: Record<string, unknown>) {
  try {
    return await session.send(stype, payload);
  } catch (error) {
    if (error instanceof SchemaFidelityError) {
      // Fix the payload and retry
      console.error('Validation errors:', error.validationErrors);
      throw error;

    } else if (error instanceof QomBreachError) {
      // Quality issue - log and potentially retry with different prompt
      console.warn('QoM breach:', error.failures);
      throw error;

    } else if (error instanceof NegotiationError) {
      // Incompatible server - cannot proceed
      console.error('Server incompatible:', error.reason);
      throw error;

    } else if (error instanceof ConnectionError) {
      // Network issue - retry with backoff
      console.warn('Connection lost, retrying...');
      await session.connect();
      return await session.send(stype, payload);

    } else if (error instanceof HashMismatchError) {
      // Integrity violation - do not trust the data
      console.error('Data integrity compromised!');
      throw error;

    } else if (error instanceof PolicyDeniedError) {
      // Policy blocked - check remediation
      console.error(`Policy ${error.policy}: ${error.remediation}`);
      throw error;

    } else if (error instanceof MplError) {
      // Unknown MPL error
      console.error('MPL error:', error.code, error.message);
      throw error;

    } else {
      // Non-MPL error (network timeout, etc.)
      throw error;
    }
  }
}

Type Guard Pattern

function isMplError(error: unknown): error is MplError {
  return error instanceof MplError;
}

function isRetryable(error: unknown): boolean {
  if (!isMplError(error)) return false;
  return error.code === 'E-CONNECTION';
}

JSON Serialization for Logging

All errors support toJSON() for structured logging:

try {
  await session.send(stype, payload);
} catch (error) {
  if (error instanceof MplError) {
    // Structured log entry
    logger.error({
      ...error.toJSON(),
      timestamp: new Date().toISOString(),
      requestId: currentRequestId,
    });
  }
}

See Also

  • Client - How errors are thrown in production mode
  • Session - Errors during connection and messaging
  • Validation - Schema validation that produces SchemaFidelityError
  • QoM - Profile evaluation that produces QomBreachError
  • Hashing - Hash verification that produces HashMismatchError