Blog
`NamedError` class in opencode codebase.

`NamedError` class in opencode codebase.

In this article, we review NamedError class in opencode codebase. We will look at:

  1. NamedError class definition

  2. NamedError.create example

I study patterns used in an open source project found on Github Trending. For this week, I reviewed some parts of opencode codebase and wrote this article.

NamedError class definition

In opencode/packages/opencode/src/util/error.ts, you will find the below declaration:

import z from "zod/v4"
// import { Log } from "./log"

// const log = Log.create()

export abstract class NamedError extends Error {
  abstract schema(): z.core.$ZodType
  abstract toObject(): { name: string; data: any }

  static create<Name extends string, Data extends z.core.$ZodType>(name: Name, data: Data) {
  }

  public static readonly Unknown = NamedError.create(
    "UnknownError",
    z.object({
      message: z.string(),
    }),
  )
}

create

Create is defined as shown below:

static create<Name extends string, Data extends z.core.$ZodType>(name: Name, data: Data) {
  const schema = z
    .object({
      name: z.literal(name),
      data,
    })
    .meta({
      ref: name,
    })
  const result = class extends NamedError {
    public static readonly Schema = schema

    public readonly name = name as Name

    constructor(
      public readonly data: z.input<Data>,
      options?: ErrorOptions,
    ) {
      super(name, options)
      this.name = name
    }

    static isInstance(input: any): input is InstanceType<typeof result> {
      return "name" in input && input.name === name
    }

    schema() {
      return schema
    }

    toObject() {
      return {
        name: name,
        data: this.data,
      }
    }
  }
  Object.defineProperty(result, "name", { value: name })
  return result
}

Accepts two parameters:

  1. name

  2. data

result is assigned a class as shown below:

    const result = class extends NamedError {

Defines readonly variables

public static readonly Schema = schema

public readonly name = name as Name

constructor is initialized:

constructor(
  public readonly data: z.input<Data>,
  options?: ErrorOptions,
) {
  super(name, options)
  this.name = name
}

and has the below methods defined within result object

static isInstance(input: any): input is InstanceType<typeof result> {
  return "name" in input && input.name === name
}

schema() {
  return schema
}

toObject() {
  return {
    name: name,
    data: this.data,
  }
}

Finally result is returned by this NamedError.create method:

Object.defineProperty(result, "name", { value: name })
return result

NamedError.create example

In sst/opencode/packages/opencode/src/lsp/client.ts at L20, you will find the below code:

import { NamedError } from "../util/error"
...
export namespace LSPClient {
  const log = Log.create({ service: "lsp.client" })
  ...
  export const InitializeError = NamedError.create(
    "LSPInitializeError",
    z.object({
      serverID: z.string(),
    }),
  )

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/sst/opencode/blob/dev/packages/opencode/src/util/error.ts#L6

  2. https://github.com/sst/opencode/blob/dev/packages/opencode/src/lsp/client.ts#L20