How Supermemory Handles Errors: Typed Classes, Centralized Wrappers, and Consistent HTTP Responses
Supermemory implements a layered error-handling strategy using typed error classes, centralized request wrappers, and consistent HTTP response patterns across its Raycast extension, browser extension, and Next.js backend.
Error handling in modern full-stack applications requires discipline across multiple runtimes and clients. In the supermemoryai/supermemory repository, the development team established a robust error management architecture that spans TypeScript frontend clients, Next.js API routes, and external service integrations. This article examines how Supermemory handles errors through typed abstractions, centralized request logic, and consistent JSON contracts that enable reliable debugging and user feedback.
Typed Error Classes for Type-Safe Discrimination
Supermemory defines custom error classes that extend the native Error object to enable precise instanceof checking at runtime. These classes are distributed across client applications to provide context-specific error information.
In apps/raycast-extension/src/api.ts (lines 56‑63), the SupermemoryAPIError class captures HTTP status codes and response messages:
class SupermemoryAPIError extends Error {
constructor(
message: string,
public status: number
) {
super(message);
this.name = "SupermemoryAPIError";
}
}
The same file defines AuthenticationError (lines 66‑70) to specifically signal invalid or missing API keys. Meanwhile, the browser extension uses a base ExtensionError class defined in apps/browser-extension/utils/types.ts (line 119), which SupermemoryAPIError extends (line 137) for extension-specific contexts.
This hierarchy allows client code to distinguish between authentication failures, API-level errors, and generic runtime exceptions without parsing error strings.
Centralized Request Wrappers in the Raycast Extension
All HTTP calls from the Raycast extension flow through a single makeAuthenticatedRequest function in apps/raycast-extension/src/api.ts (lines 78‑135). This wrapper implements a consistent error-handling pipeline:
- Injects the Authorization header (
Bearer <apiKey>) for authenticated endpoints. - Validates the response status via
response.okand extracts detailed messages from JSON error bodies when available. - Throws typed errors:
AuthenticationErrorfor 401 responses andSupermemoryAPIErrorfor other non-2xx statuses. - Catches network-level exceptions and re-throws them as
SupermemoryAPIErrorinstances with a "Network error" prefix.
This centralization ensures that every API call benefits from identical error transformation logic, preventing inconsistent error handling across different features.
Next.js API Route Error Patterns
Serverless routes in apps/web/app/api/ follow a standardized try/catch pattern that combines structured logging with HTTP-appropriate status codes.
Generic Internal Server Errors
The onboarding research endpoint in apps/web/app/api/onboarding/research/route.ts (lines 70‑73) catches unexpected failures and returns a generic 500 response:
try {
// ...logic...
} catch (error) {
console.error("Research error:", error);
return Response.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
Input Validation and External Service Errors
The OG metadata scraper in apps/web/app/api/og/route.ts implements granular status code selection:
- Returns 400 Bad Request for malformed URLs (lines 42‑57).
- Returns 500 Internal Server Error for unexpected fetch failures (lines 71‑77, 92‑98).
Similarly, the content extraction route in apps/web/app/api/onboarding/extract-content/route.ts returns 400 for malformed payloads (lines 16‑28) and 500 for downstream API failures (lines 43‑60), logging each error context for debugging.
Middleware-Level Authentication Guards
The Next.js middleware in apps/web/middleware.ts (lines 21‑30) provides early error termination for unauthenticated API requests. If a request path starts with /api/ and no session cookie is present, the middleware immediately returns:
{ "error": "Unauthorized" }
With an HTTP 401 Unauthorized status. This prevents unauthenticated traffic from reaching application logic, reducing unnecessary server load and potential security exposure.
Library-Level Logging and Observability
Low-level utilities in packages/tools/ catch internal errors, log structured metadata, and re-throw wrapped errors that bubble up to route handlers. In packages/tools/src/openai/tools.ts (lines 270‑306), the error handler uses a shared logger:
catch (error) {
logger.error("Error generating response", {
error: error instanceof Error ? error.message : "Unknown error",
});
throw new Error(`Supermemory API request failed: ${error}`);
}
The Vercel middleware in packages/tools/src/vercel/middleware.ts (lines 152‑158) follows an identical pattern. These logs feed into Sentry, configured in apps/web/next.config.ts, enabling production monitoring of uncaught exceptions and downstream service failures.
Consistent Error Response Contracts
All JSON error responses across the Supermemory ecosystem share a uniform shape:
{ "error": "<human-readable message>" }
This contract allows the Raycast extension, browser extension, and web UI to parse error responses without implementing custom parsers for each endpoint. Clients can reliably extract user-facing messages from the error property regardless of whether the failure originated from input validation, authentication, or internal server errors.
Practical Implementation: Handling Errors in the Raycast Client
When consuming the Supermemory API from the Raycast extension, developers leverage the typed error classes for precise user feedback:
import { fetchProjects, addMemory, SupermemoryAPIError, AuthenticationError } from "./api";
async function listProjects() {
try {
const projects = await fetchProjects();
console.log("Projects:", projects);
} catch (err) {
if (err instanceof SupermemoryAPIError) {
console.error(`API error (${err.status}): ${err.message}`);
// Display status-specific UI feedback
} else if (err instanceof AuthenticationError) {
console.error("Invalid API key:", err.message);
// Prompt user to update credentials
} else {
console.error("Unexpected error:", err);
// Generic error fallback
}
}
}
async function createMemory() {
try {
const memory = await addMemory({
content: "Important note from meeting",
title: "Meeting notes",
});
console.log("Memory added:", memory.id);
} catch (err) {
console.error(err instanceof Error ? err.message : "Unknown error");
}
}
This pattern enables UI components to display contextual error messages—such as "Invalid API key" versus "Network error"—based on the specific error type caught.
Summary
- Typed error classes (
SupermemoryAPIError,AuthenticationError,ExtensionError) enable type-safe error discrimination viainstanceofchecks. - Centralized request wrappers in
apps/raycast-extension/src/api.tsensure consistent header injection, status validation, and error transformation. - Next.js API routes return specific HTTP status codes (400 for validation, 401 for authentication, 500 for server errors) with consistent JSON bodies.
- Middleware guards in
apps/web/middleware.tsblock unauthenticated requests early with 401 responses. - Library-level logging in
packages/tools/captures detailed error context for Sentry monitoring while propagating clean error messages to callers. - Uniform error contracts (
{ "error": "message" }) simplify client-side error parsing across all Supermemory applications.
Frequently Asked Questions
What specific error classes does Supermemory define for API failures?
Supermemory defines SupermemoryAPIError (for general HTTP errors with status codes) and AuthenticationError (for invalid API keys) in apps/raycast-extension/src/api.ts. The browser extension additionally uses an ExtensionError base class defined in apps/browser-extension/utils/types.ts to create hierarchical error types specific to extension contexts.
How does Supermemory distinguish between authentication and network errors?
The makeAuthenticatedRequest function in apps/raycast-extension/src/api.ts checks the HTTP status code: it throws AuthenticationError for 401 responses and SupermemoryAPIError for other non-2xx statuses. Network-level exceptions (fetch failures) are caught and re-thrown as SupermemoryAPIError instances with a "Network error" prefix, allowing callers to handle connectivity issues separately from credential problems.
What HTTP status codes does Supermemory return for different error scenarios?
Supermemory returns 400 Bad Request for malformed input (e.g., invalid URLs in the OG scraper), 401 Unauthorized for missing or invalid authentication (from middleware or API routes), and 500 Internal Server Error for unexpected runtime failures or downstream service errors. This mapping is implemented consistently across routes like apps/web/app/api/og/route.ts and apps/web/app/api/onboarding/extract-content/route.ts.
How does Supermemory monitor production errors?
Supermemory integrates Sentry via apps/web/next.config.ts to capture uncaught exceptions. Additionally, library code in packages/tools/src/openai/tools.ts and packages/tools/src/vercel/middleware.ts uses a shared logger to record error details before re-throwing, ensuring that both handled and unhandled errors are observable in production environments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →