Skip to main content
Shield exports typed errors for structured error handling. This allows you to catch and respond to security events programmatically.

Typed Error Classes

Shield provides three error classes for different security scenarios:

ShieldError

Base error class for all Shield errors.
export class ShieldError extends Error {
  readonly code: string;

  constructor(message: string, code: string) {
    super(message);
    this.name = "ShieldError";
    this.code = code;
  }
}

InjectionDetectedError

Thrown when prompt injection is detected in user input (when onDetection: "block").
export class InjectionDetectedError extends ShieldError {
  readonly risk: string;
  readonly categories: string[];

  constructor(risk: string, categories: string[]) {
    super(
      `Prompt injection detected (${risk} risk): ${categories.join(", ")}`,
      "INJECTION_DETECTED"
    );
    this.name = "InjectionDetectedError";
    this.risk = risk;
    this.categories = categories;
  }
}
Properties:
  • risk: Risk level ("low", "medium", "high", or "critical")
  • categories: Array of attack categories detected (e.g. ["role_hijacking", "instruction_override"])
  • code: Always "INJECTION_DETECTED"

LeakDetectedError

Thrown when system prompt leakage is detected in model output (when throwOnLeak: true).
export class LeakDetectedError extends ShieldError {
  readonly confidence: number;
  readonly fragmentCount: number;

  constructor(confidence: number, fragmentCount: number) {
    super(
      `System prompt leak detected (confidence: ${Math.round(confidence * 100)}%, ${fragmentCount} fragment${fragmentCount !== 1 ? "s" : ""})`,
      "LEAK_DETECTED"
    );
    this.name = "LeakDetectedError";
    this.confidence = confidence;
    this.fragmentCount = fragmentCount;
  }
}
Properties:
  • confidence: Leak confidence score (0-1)
  • fragmentCount: Number of system prompt fragments detected in output
  • code: Always "LEAK_DETECTED"

Error Handling Patterns

Catching Injection and Leak Errors

import { 
  ShieldError, 
  InjectionDetectedError, 
  LeakDetectedError 
} from "@zeroleaks/shield";

try {
  const client = shieldOpenAI(openai, { 
    systemPrompt: "...", 
    throwOnLeak: true 
  });
  await client.chat.completions.create({ ... });
} catch (error) {
  if (error instanceof InjectionDetectedError) {
    console.log(error.risk, error.categories);
  }
  if (error instanceof LeakDetectedError) {
    console.log(error.confidence, error.fragmentCount);
  }
}

Logging Security Events

import { InjectionDetectedError, LeakDetectedError } from "@zeroleaks/shield";

try {
  const response = await shieldedClient.chat.completions.create({
    model: "gpt-5.3-codex",
    messages: [{ role: "user", content: userInput }],
  });
} catch (error) {
  if (error instanceof InjectionDetectedError) {
    // Log security event to monitoring system
    logger.warn("Prompt injection detected", {
      risk: error.risk,
      categories: error.categories,
      userId: currentUser.id,
    });
    return { error: "Invalid input detected" };
  }
}

Custom Error Handling by Risk Level

try {
  const response = await shieldedClient.chat.completions.create(params);
} catch (error) {
  if (error instanceof InjectionDetectedError) {
    switch (error.risk) {
      case "critical":
      case "high":
        // Block request and flag account
        await flagUserAccount(userId);
        throw new Error("Request blocked");
      
      case "medium":
        // Log and notify security team
        await notifySecurityTeam(error);
        throw error;
      
      case "low":
        // Log only
        logger.info("Low-risk pattern detected", { categories: error.categories });
        throw error;
    }
  }
}

Detection Modes

Shield supports two detection modes via the onDetection option:

Block Mode (default)

Throws InjectionDetectedError when injection is detected:
const client = shieldOpenAI(openai, {
  systemPrompt: "You are a helpful assistant.",
  onDetection: "block", // default
});

// Throws InjectionDetectedError on malicious input
await client.chat.completions.create({ ... });

Warn Mode

Logs warnings without throwing, allowing requests to proceed:
const client = shieldOpenAI(openai, {
  systemPrompt: "You are a helpful assistant.",
  onDetection: "warn", // only log, don't throw
  onInjectionDetected: (result) => {
    console.warn("Injection detected but allowing:", result);
  },
});

// Request proceeds even with malicious input (not recommended for production)
await client.chat.completions.create({ ... });
Using onDetection: "warn" in production is not recommended. It should only be used during development, testing, or when you have additional security controls in place.

Leak Detection Configuration

By default, leaked content is redacted. Enable throwOnLeak to throw an error instead:
const client = shieldOpenAI(openai, {
  systemPrompt: "You are a financial advisor. Never share account numbers.",
  throwOnLeak: true, // throw instead of redacting
});

try {
  const response = await client.chat.completions.create({ ... });
} catch (error) {
  if (error instanceof LeakDetectedError) {
    logger.error("System prompt leaked", {
      confidence: error.confidence,
      fragments: error.fragmentCount,
    });
    // Return generic error to user
    return { error: "Unable to process request" };
  }
}
For most applications, redaction (default) is preferred over throwing. Use throwOnLeak: true when you need strict guarantees that no leaked content reaches users.

Error Property Reference

InjectionDetectedError Properties

PropertyTypeDescription
name"InjectionDetectedError"Error class name
code"INJECTION_DETECTED"Error code
messagestringHuman-readable error message
riskstringRisk level: "low", "medium", "high", or "critical"
categoriesstring[]Attack categories detected

LeakDetectedError Properties

PropertyTypeDescription
name"LeakDetectedError"Error class name
code"LEAK_DETECTED"Error code
messagestringHuman-readable error message
confidencenumberLeak confidence score (0-1)
fragmentCountnumberNumber of leaked fragments detected

Build docs developers (and LLMs) love