# Error Handling Mechanisms for Exports in the Instagit Design.md Codebase

> Explore Instagit Design.md's robust export error handling. Discover Zod enums, discriminated results, and custom I/O errors to prevent uncaught exceptions and ensure type safety.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-07-02

---

**The google-labs-code/design.md repository implements a strict, type-safe strategy for export error handling through Zod-based enums, discriminated result objects, and custom I/O error classes that eliminate uncaught exceptions.**

The [`google-labs-code/design.md`](https://github.com/google-labs-code/design.md/blob/main/google-labs-code/design.md) project—also referred to as Instagit—provides a CLI and programmatic API for linting and parsing design system documentation. Understanding the error handling mechanisms for exports is critical when integrating with its public API surface, as every exported handler guarantees explicit error propagation through structured result types rather than traditional exception throwing.

## Typed Error Enums for Parser and Model Validation

The codebase defines closed sets of error identifiers using Zod schemas. In [`packages/cli/src/linter/parser/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/parser/spec.ts), the `ParserErrorCode` enum provides identifiers such as `EMPTY_CONTENT` and `NO_YAML_FOUND`. Similarly, [`packages/cli/src/linter/model/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/spec.ts) exports `ModelErrorCode` for model-level failures.

Each validation failure returns a structured error object containing `{ code, message, recoverable }`. This design allows consumers to perform exhaustive switch statements on `error.code` without fragile string-matching. When Zod schemas like `ParserInputSchema` detect malformed payloads, the resulting `ZodError` is caught internally and transformed into these typed enum instances.

## Result Objects Replace Thrown Exceptions

Every exported handler in the repository follows a strict contract: **never throw, always return a result**. The concrete implementations—`ParserHandler` in [`packages/cli/src/linter/parser/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/parser/handler.ts) and `ModelHandler` in [`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts)—return discriminated unions shaped as `{ success: true, data: ... }` or `{ success: false, error: ... }`.

This pattern appears in `ParserResult`, `ModelResult`, and `LintResult` (defined in [`packages/cli/src/linter/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/lint.ts)). By returning a `success` boolean flag alongside either data or error details, the API forces callers to handle failure paths explicitly, eliminating unexpected runtime exceptions.

## Custom Error Classes for File System Operations

For I/O boundaries, the codebase exports `FileReadError` from [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts). When the `readInput` function encounters file system issues, it instantiates this class with the original `filePath` and underlying cause, exposing a `friendlyMessage` property for user-facing diagnostics (e.g., "file not found" or "permission denied").

Unlike the validation errors that populate result objects, `FileReadError` is thrown immediately to signal unrecoverable infrastructure failures. Consumers should catch this specific class to distinguish between parsing logic errors and external system failures.

## Graceful Fallbacks in CLI Utilities

The utility functions in [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) implement defensive programming to prevent CLI crashes. Functions like `formatOutput`, `serializeDesignSystem`, and `diffMaps` never throw exceptions; instead, they return deterministic default values (empty strings, empty arrays, or null diffs) when processing malformed or incomplete data. This ensures the CLI remains operational even when individual exports encounter unexpected inputs.

## Practical Implementation Examples

The following examples demonstrate how to consume the exported API while respecting its error handling contracts.

### Consuming a Parser Export Safely

```typescript
import { ParserSpec, ParserInput } from '@instagit/linter/parser';
import { ParserResult } from '@instagit/linter/parser/spec';

async function runParser(file: string) {
  const input: ParserInput = { content: await readFile(file) };
  const parser: ParserSpec = new ParserHandler();
  const result: ParserResult = parser.execute(input);

  if (!result.success) {
    switch (result.error.code) {
      case 'EMPTY CONTENT':
        console.error('The file is empty.');
        break;
      case 'YAML PARSE ERROR':
        console.error('YAML could not be parsed:', result.error.message);
        break;
      default:
        console.error('Unexpected parser error:', result.error);
    }
    return;
  }

  console.log('Parsed design system:', result.data);
}

```

*Source: Implementation follows `ParserResult` definitions in [`packages/cli/src/linter/parser/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/parser/spec.ts).*

### Handling File-Read Errors

```typescript
import { readInput, FileReadError } from '@instagit/utils';

async function loadDesign(path: string) {
  try {
    const raw = await readInput(path);
    // Process raw DESIGN.md content
  } catch (err) {
    if (err instanceof FileReadError) {
      console.error(err.friendlyMessage);
    } else {
      console.error('Unexpected error:', err);
    }
  }
}

```

*Source: `FileReadError` class and `readInput` implementation in [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts).*

### Using the Linter Result Object

```typescript
import { lintDesignSystem } from '@instagit/cli';
import type { LintResult } from '@instagit/linter';

async function lintFile(file: string) {
  const result: LintResult = await lintDesignSystem(file);

  if (!result.success) {
    console.error('Linting failed:', result.error);
    return;
  }

  console.log('Lint summary:', result.summary);
  result.findings.forEach(f => {
    console.log(`[${f.severity}] ${f.path ?? ''}: ${f.message}`);
  });
}

```

*Source: `LintResult` interface defined in [`packages/cli/src/linter/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/lint.ts).*

## Summary

- **Typed error enums** (`ParserErrorCode`, `ModelErrorCode`) in [`spec.ts`](https://github.com/google-labs-code/design.md/blob/main/spec.ts) files provide exhaustive, type-safe error classification.
- **Result objects** (`ParserResult`, `ModelResult`, `LintResult`) replace exceptions with explicit `{ success, data/error }` shapes exported by handler implementations.
- **Custom I/O errors** (`FileReadError` in [`utils.ts`](https://github.com/google-labs-code/design.md/blob/main/utils.ts)) capture infrastructure failures with contextual metadata and user-friendly messages.
- **Graceful fallbacks** in utilities like `formatOutput` and `diffMaps` ensure the CLI never crashes on malformed inputs.

## Frequently Asked Questions

### What happens when Zod validation fails in the exported handlers?

When an input fails Zod schema validation (such as `ParserInputSchema`), the handler catches the resulting `ZodError` and transforms it into a structured error object containing a specific `ParserErrorCode` or `ModelErrorCode`, then returns it inside a `{ success: false, error: ... }` result object. This prevents validation failures from propagating as uncaught exceptions.

### How does `FileReadError` differ from `ParserErrorCode` errors?

`FileReadError` is a custom class exported from [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) that is **thrown** to signal unrecoverable file system issues like missing files or permission errors. In contrast, `ParserErrorCode` errors are **returned** within result objects to represent logical validation failures inside the parser or model handlers.

### Why does the design.md API avoid throwing exceptions?

The API avoids throwing exceptions to ensure **predictable control flow** and **type safety**. By returning discriminated result unions from handlers like `ParserHandler.execute`, the codebase forces consumers to explicitly check `result.success` before accessing data, eliminating runtime surprises and aligning with TypeScript's type narrowing capabilities.

### Which utilities guarantee non-crashing behavior even with malformed inputs?

The CLI utility functions `formatOutput`, `serializeDesignSystem`, and `diffMaps` in [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) are designed to never throw. They return deterministic fallback values—such as empty strings or empty diffs—when receiving malformed data, ensuring the exported CLI surface remains stable regardless of input quality.