or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/langsmith@0.4.x

docs

index.md
tile.json

tessl/npm-langsmith

tessl install tessl/npm-langsmith@0.4.3

TypeScript client SDK for the LangSmith LLM tracing, evaluation, and monitoring platform.

error-handling.mddocs/guides/

Error Handling Reference

Comprehensive guide to handling errors in LangSmith SDK operations.

Overview

The LangSmith SDK can encounter various errors during API operations. This guide provides systematic error handling patterns, HTTP status code meanings, recovery strategies, and production-ready error handling code.

HTTP Status Codes

Status Code Reference

CodeMeaningCommon CausesRecovery Strategy
200SuccessRequest completed successfullyContinue normally
400Bad RequestInvalid parameters, malformed data, validation errorsValidate inputs, check parameter types and formats
401UnauthorizedMissing API key, invalid API key, expired keyCheck LANGCHAIN_API_KEY env var, regenerate key
403ForbiddenInsufficient permissions, wrong workspaceVerify API key scopes, check workspace ID
404Not FoundResource doesn't exist (run, dataset, project)Check IDs, verify resource was created
409ConflictResource already exists, concurrent modificationUse upsert flag, check existence first, implement optimistic locking
429Rate LimitedToo many requests in time windowImplement exponential backoff, reduce request rate, increase delays
500Internal Server ErrorLangSmith service issueRetry with backoff, check status page, contact support
502Bad GatewayProxy/gateway issueRetry with backoff
503Service UnavailableTemporary service outage, maintenanceRetry with backoff, implement fallback, check status
504Gateway TimeoutRequest took too longRetry, increase timeout, simplify request

Error Handling Patterns

Pattern 1: Basic Error Handling

Handle common error scenarios with appropriate messages.

import { Client } from "langsmith";

const client = new Client();

try {
  const run = await client.readRun(runId);
  console.log(run.name);
} catch (error) {
  // Type-specific handling
  if (error.status === 404) {
    console.error("Run not found - verify run ID:", runId);
  } else if (error.status === 401) {
    console.error("Authentication failed - check LANGCHAIN_API_KEY environment variable");
  } else if (error.status === 429) {
    console.error("Rate limit exceeded - reduce request frequency");
  } else if (error.status >= 500) {
    console.error("Server error - LangSmith service may be experiencing issues");
  } else {
    console.error("API error:", error.message);
  }
}

Pattern 2: Retry with Exponential Backoff

Automatically retry transient errors with increasing delays.

import { Client } from "langsmith";
import type { Run } from "langsmith/schemas";

async function readRunWithRetry(
  client: Client,
  runId: string,
  maxRetries = 3
): Promise<Run> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await client.readRun(runId);
    } catch (error) {
      // Don't retry on permanent errors
      if (error.status === 404 || error.status === 401 || error.status === 403) {
        throw error; // Permanent failure - don't retry
      }

      // Retry on rate limits and transient errors
      if (i < maxRetries - 1 && (error.status === 429 || error.status >= 500)) {
        const delay = Math.pow(2, i) * 1000; // Exponential backoff: 1s, 2s, 4s
        console.log(`Retry attempt ${i + 1}/${maxRetries} after ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      // Max retries exceeded or non-retryable error
      throw error;
    }
  }

  throw new Error("Max retries exceeded");
}

// Usage
try {
  const run = await readRunWithRetry(client, runId);
  console.log("Run retrieved:", run.name);
} catch (error) {
  console.error("Failed after retries:", error.message);
}

Retry Configuration:

// Configurable retry logic
interface RetryConfig {
  maxRetries: number;
  baseDelay: number;
  maxDelay: number;
  retryableStatuses: number[];
}

const defaultRetryConfig: RetryConfig = {
  maxRetries: 3,
  baseDelay: 1000,
  maxDelay: 30000,
  retryableStatuses: [429, 500, 502, 503, 504]
};

async function withRetry<T>(
  operation: () => Promise<T>,
  config: RetryConfig = defaultRetryConfig
): Promise<T> {
  for (let i = 0; i < config.maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      const shouldRetry =
        i < config.maxRetries - 1 &&
        config.retryableStatuses.includes(error.status);

      if (!shouldRetry) {
        throw error;
      }

      const delay = Math.min(
        Math.pow(2, i) * config.baseDelay,
        config.maxDelay
      );

      console.log(`Retrying after ${delay}ms (attempt ${i + 1}/${config.maxRetries})`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw new Error("Max retries exceeded");
}

// Usage
const run = await withRetry(() => client.readRun(runId));

Pattern 3: Graceful Degradation

Continue operation even if tracing fails.

async function traceWithFallback(operation: () => Promise<any>) {
  const client = new Client();

  try {
    // Attempt to create trace
    await client.createRun({
      name: "operation",
      run_type: "chain",
      inputs: {},
      start_time: Date.now(),
    });

    const result = await operation();

    await client.updateRun(runId, {
      end_time: Date.now(),
      outputs: { result }
    });

    return result;
  } catch (error) {
    // If tracing fails, log warning but continue operation
    console.warn("Tracing unavailable, continuing without tracing:", error.message);

    // Still execute the operation
    return await operation();
  }
}

// Usage
const result = await traceWithFallback(async () => {
  return await criticalBusinessLogic();
});

Optional Tracing Pattern:

import { Client } from "langsmith";

class OptionalTracingClient {
  private client?: Client;
  private enabled: boolean;

  constructor() {
    try {
      this.client = new Client();
      this.enabled = !!process.env.LANGCHAIN_API_KEY;
    } catch (error) {
      console.warn("LangSmith client initialization failed:", error.message);
      this.enabled = false;
    }
  }

  async createRun(run: any) {
    if (!this.enabled || !this.client) return;

    try {
      await this.client.createRun(run);
    } catch (error) {
      console.warn("Failed to create run, continuing:", error.message);
    }
  }

  async flush() {
    if (!this.enabled || !this.client) return;

    try {
      await this.client.awaitPendingTraceBatches();
    } catch (error) {
      console.warn("Failed to flush traces:", error.message);
    }
  }
}

// Usage
const tracingClient = new OptionalTracingClient();
await tracingClient.createRun({...}); // Never throws

Pattern 4: Per-Item Error Handling in Async Iteration

Handle errors during iteration without stopping the loop.

import { Client } from "langsmith";

async function safeListRuns(client: Client, projectName: string) {
  try {
    for await (const run of client.listRuns({ projectName })) {
      try {
        // Process each run safely
        await processRun(run);
      } catch (error) {
        // GOOD: Handle per-run errors without stopping iteration
        console.error(`Error processing run ${run.id}:`, error.message);
        // Continue to next run
      }
    }
  } catch (error) {
    // Handle iteration-level errors (project not found, auth failure)
    if (error.status === 404) {
      console.error("Project not found:", projectName);
    } else if (error.status === 401) {
      console.error("Authentication failed - check API key");
    } else {
      console.error("Failed to list runs:", error.message);
    }

    // Optionally rethrow if critical
    throw error;
  }
}

// Usage
try {
  await safeListRuns(client, "my-project");
  console.log("All runs processed successfully");
} catch (error) {
  console.error("Fatal error during run processing");
}

Pattern 5: Pagination Safety with Limits

Prevent out-of-memory errors when querying large result sets.

import { Client } from "langsmith";
import type { Run } from "langsmith/schemas";

async function getAllRuns(
  client: Client,
  projectName: string,
  maxRuns = 10000
): Promise<Run[]> {
  const runs: Run[] = [];

  try {
    for await (const run of client.listRuns({ projectName, limit: maxRuns })) {
      runs.push(run);

      // Safety limit to prevent memory issues
      if (runs.length >= maxRuns) {
        console.warn(`Reached maximum run limit of ${maxRuns}`);
        break;
      }
    }
  } catch (error) {
    console.error("Error fetching runs:", error.message);
    // Return partial results rather than failing completely
    console.log(`Returning ${runs.length} runs before error`);
  }

  return runs;
}

// Usage with processing
async function processAllRuns(client: Client, projectName: string) {
  const runs = await getAllRuns(client, projectName, 5000);
  console.log(`Processing ${runs.length} runs`);

  for (const run of runs) {
    await processRun(run);
  }
}

Streaming Alternative (Better for Large Sets):

async function processRunsStreaming(client: Client, projectName: string) {
  let processedCount = 0;
  const maxProcessed = 10000;

  try {
    for await (const run of client.listRuns({ projectName })) {
      await processRun(run); // Process one at a time
      processedCount++;

      if (processedCount >= maxProcessed) {
        console.warn(`Processed maximum ${maxProcessed} runs`);
        break;
      }

      // Progress logging
      if (processedCount % 100 === 0) {
        console.log(`Processed ${processedCount} runs...`);
      }
    }
  } catch (error) {
    console.error(`Error after processing ${processedCount} runs:`, error.message);
  }

  return processedCount;
}

Pattern 6: Validation Before API Calls

Validate inputs before making API requests.

import { Client } from "langsmith";

async function createRunSafely(client: Client, params: any) {
  // Validate required fields
  if (!params.name) {
    throw new Error("Run name is required");
  }

  if (!params.run_type) {
    throw new Error("Run type is required");
  }

  // Validate run_type value
  const validRunTypes = ["llm", "chain", "tool", "retriever", "embedding", "prompt", "parser"];
  if (!validRunTypes.includes(params.run_type)) {
    throw new Error(`Invalid run_type: ${params.run_type}. Must be one of: ${validRunTypes.join(", ")}`);
  }

  // Validate timestamps
  if (params.start_time && params.end_time && params.start_time > params.end_time) {
    throw new Error("start_time cannot be greater than end_time");
  }

  try {
    await client.createRun(params);
  } catch (error) {
    if (error.status === 400) {
      console.error("Validation failed on server:", error.message);
      console.error("Params:", JSON.stringify(params, null, 2));
    }
    throw error;
  }
}

Pattern 7: Timeout Handling

Handle long-running operations that may timeout.

import { Client } from "langsmith";

// Configure custom timeout
const client = new Client({
  timeout_ms: 30000 // 30 seconds
});

async function operationWithTimeout(client: Client, operation: () => Promise<any>) {
  try {
    return await operation();
  } catch (error) {
    if (error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT') {
      console.error("Operation timed out - consider:");
      console.error("1. Increasing timeout_ms in client config");
      console.error("2. Breaking operation into smaller chunks");
      console.error("3. Using pagination/limits");
      throw new Error("Operation timeout");
    }
    throw error;
  }
}

Pattern 8: Batch Operation Error Handling

Handle errors in batch operations.

import { Client } from "langsmith";

async function batchIngestWithErrorHandling(client: Client, runs: any[]) {
  // Validate batch size
  if (runs.length > 1000) {
    console.warn("Large batch - consider splitting into smaller chunks");
  }

  try {
    await client.batchIngestRuns({
      post: runs
    });
    console.log(`Successfully ingested ${runs.length} runs`);
  } catch (error) {
    if (error.status === 413) {
      // Payload too large
      console.error("Batch too large, splitting into chunks...");

      const chunkSize = Math.ceil(runs.length / 2);
      const chunks = [];
      for (let i = 0; i < runs.length; i += chunkSize) {
        chunks.push(runs.slice(i, i + chunkSize));
      }

      for (const chunk of chunks) {
        await batchIngestWithErrorHandling(client, chunk); // Recursive
      }
    } else if (error.status === 400) {
      console.error("Validation error in batch:");
      console.error("Check that all runs have required fields");
      throw error;
    } else {
      throw error;
    }
  }
}

Common Errors and Solutions

Error: "Traces not appearing in LangSmith UI"

Possible Causes:

  1. API key not set or invalid
  2. Traces not flushed before process exit
  3. Network connectivity issues
  4. Wrong project name
  5. Tracing disabled or sampled out

Solutions:

// 1. Verify API key
const config = Client.getDefaultClientConfig();
console.log("API URL:", config.apiUrl);
console.log("API Key configured:", !!config.apiKey);
console.log("API Key prefix:", config.apiKey?.substring(0, 8) + "...");

// 2. Ensure flush before exit
await client.awaitPendingTraceBatches();

// 3. Test connectivity
try {
  const projects = await client.listProjects({ limit: 1 });
  console.log("API connectivity: OK");
} catch (error) {
  console.error("Cannot reach LangSmith API:", error.message);
}

// 4. Verify project name
const projectName = process.env.LANGCHAIN_PROJECT || "default";
console.log("Using project:", projectName);

// 5. Check sampling
const client = new Client({
  tracingSamplingRate: 1.0 // Force 100% for debugging
});

Error: "Import errors with traceable"

Cause: Using wrong import path.

Don't:

// ERROR: traceable is not exported from main package
import { traceable } from "langsmith";

Do:

// CORRECT: Use subpath export
import { traceable } from "langsmith/traceable";

All Subpath Exports:

import { Client, RunTree, Cache, uuid7 } from "langsmith";
import { traceable, getCurrentRunTree } from "langsmith/traceable";
import { evaluate, evaluateComparative } from "langsmith/evaluation";
import { wrapOpenAI } from "langsmith/wrappers/openai";
import { wrapAnthropic } from "langsmith/wrappers/anthropic";
import { wrapAISDK } from "langsmith/experimental/vercel";
import { createAnonymizer } from "langsmith/anonymizer";
import { getLangchainCallbacks } from "langsmith/langchain";
import { test } from "langsmith/jest"; // or langsmith/vitest

Error: "Dataset not found"

Cause: Dataset doesn't exist or wrong identifier.

Solution:

import { Client } from "langsmith";

const client = new Client();

// Check existence before using
async function getOrCreateDataset(name: string) {
  try {
    // Try to read existing dataset
    return await client.readDataset({ datasetName: name });
  } catch (error) {
    if (error.status === 404) {
      // Dataset doesn't exist - create it
      console.log(`Dataset '${name}' not found, creating...`);
      return await client.createDataset({
        datasetName: name,
        description: "Auto-created dataset"
      });
    }
    throw error; // Other error - rethrow
  }
}

// Or use hasDataset
async function ensureDataset(name: string) {
  const exists = await client.hasDataset({ datasetName: name });
  if (!exists) {
    await client.createDataset({ datasetName: name });
  }
}

Error: "Run not found"

Cause: Run doesn't exist or wrong ID.

Solution:

async function readRunSafely(client: Client, runId: string) {
  try {
    return await client.readRun(runId);
  } catch (error) {
    if (error.status === 404) {
      console.error(`Run ${runId} not found. Possible reasons:`);
      console.error("1. Run hasn't been created yet");
      console.error("2. Run was deleted");
      console.error("3. Wrong run ID");
      console.error("4. Run in different workspace");
      return null;
    }
    throw error;
  }
}

Error: "Authentication failed"

Cause: Missing or invalid API key.

Solution:

import { Client } from "langsmith";

// Validate API key at startup
function validateLangSmithConfig() {
  const apiKey = process.env.LANGCHAIN_API_KEY;

  if (!apiKey) {
    throw new Error(
      "LANGCHAIN_API_KEY environment variable is not set. " +
      "Get your API key from https://smith.langchain.com/settings"
    );
  }

  if (!apiKey.startsWith("lsv2_")) {
    console.warn(
      "API key doesn't start with 'lsv2_' - may be invalid or outdated format"
    );
  }

  return apiKey;
}

// Use at application startup
validateLangSmithConfig();
const client = new Client();

// Or: Test API key validity
async function testAPIKey(client: Client) {
  try {
    await client.listProjects({ limit: 1 });
    console.log("API key is valid");
    return true;
  } catch (error) {
    if (error.status === 401) {
      console.error("API key is invalid or expired");
      return false;
    }
    throw error;
  }
}

Error: "Rate limit exceeded"

Cause: Too many requests in short time.

Solution:

import { Client } from "langsmith";

class RateLimitedClient {
  private client: Client;
  private requestQueue: Array<() => Promise<any>> = [];
  private processing = false;
  private requestsPerSecond: number;

  constructor(requestsPerSecond = 10) {
    this.client = new Client();
    this.requestsPerSecond = requestsPerSecond;
  }

  async queueRequest<T>(operation: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.requestQueue.push(async () => {
        try {
          const result = await operation();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });

      if (!this.processing) {
        this.processQueue();
      }
    });
  }

  private async processQueue() {
    this.processing = true;
    const delayMs = 1000 / this.requestsPerSecond;

    while (this.requestQueue.length > 0) {
      const request = this.requestQueue.shift();
      if (request) {
        await request();
        await new Promise(resolve => setTimeout(resolve, delayMs));
      }
    }

    this.processing = false;
  }
}

// Usage
const rateLimitedClient = new RateLimitedClient(10); // 10 requests/sec

for (const item of items) {
  await rateLimitedClient.queueRequest(() =>
    client.createFeedback(item.runId, "rating", { score: 1 })
  );
}

Error: "Project not found"

Cause: Project doesn't exist or wrong name/ID.

Solution:

async function ensureProject(client: Client, projectName: string) {
  try {
    // Check if project exists
    const project = await client.readProject({ projectName });
    return project;
  } catch (error) {
    if (error.status === 404) {
      // Create project if it doesn't exist
      console.log(`Project '${projectName}' not found, creating...`);
      return await client.createProject({
        projectName,
        description: "Auto-created project"
      });
    }
    throw error;
  }
}

// Or use hasProject
async function getOrCreateProject(client: Client, name: string) {
  const exists = await client.hasProject({ projectName: name });

  if (!exists) {
    return await client.createProject({
      projectName: name,
      description: "Auto-created project"
    });
  }

  return await client.readProject({ projectName: name });
}

Tracing-Specific Errors

Error: "Batches delayed or not uploading"

Cause: Batching enabled but not flushed.

Solution:

import { Client } from "langsmith";

const client = new Client({
  autoBatchTracing: true
});

// Execute traced operations
await myTracedFunction();

// CRITICAL: Flush before important operations or exit
await client.awaitPendingTraceBatches();

// For debugging: disable batching temporarily
const debugClient = new Client({
  autoBatchTracing: false // Immediate upload
});

Error: "Cannot read getCurrentRunTree - no active run"

Cause: Calling getCurrentRunTree() outside traceable context.

Solution:

import { traceable, getCurrentRunTree } from "langsmith/traceable";

// Don't call outside traceable
function helper() {
  // ERROR: Not inside traceable context
  const runTree = getCurrentRunTree(); // Throws error
}

// SOLUTION 1: Use optional variant
function safeHelper() {
  const runTree = getCurrentRunTree(true); // Returns undefined if not in context
  if (runTree) {
    runTree.metadata = { helper: true };
  }
}

// SOLUTION 2: Only call within traceable
const myFunction = traceable(async () => {
  const runTree = getCurrentRunTree(); // OK: Inside traceable
  runTree.metadata = { processed: true };
}, { name: "my-function" });

Network and Connectivity Errors

Error: "ECONNREFUSED" or "Network timeout"

Cause: Cannot reach LangSmith API.

Solution:

import { Client } from "langsmith";

async function checkConnectivity() {
  const client = new Client({
    timeout_ms: 5000 // Short timeout for connectivity check
  });

  try {
    await client.listProjects({ limit: 1 });
    console.log("✓ Connected to LangSmith API");
    return true;
  } catch (error) {
    if (error.code === 'ECONNREFUSED') {
      console.error("✗ Cannot connect to LangSmith API");
      console.error("Check:");
      console.error("  1. Internet connectivity");
      console.error("  2. Firewall/proxy settings");
      console.error("  3. API URL:", client.getHostUrl());
    } else if (error.code === 'ETIMEDOUT') {
      console.error("✗ Connection timeout");
      console.error("  Consider increasing timeout_ms or checking network");
    } else {
      console.error("✗ Connection error:", error.message);
    }
    return false;
  }
}

// Use at startup
if (!(await checkConnectivity())) {
  console.log("Running in offline mode - tracing disabled");
}

Resource Exhaustion Errors

Error: Out of Memory

Cause: Accumulating too many runs or examples in memory.

Solution:

import { Client } from "langsmith";

// BAD: Accumulates all in memory
const allRuns = [];
for await (const run of client.listRuns({ projectName: "huge" })) {
  allRuns.push(run); // OOM risk
}

// GOOD: Process and discard
for await (const run of client.listRuns({ projectName: "huge" })) {
  await processRun(run);
  // run is eligible for garbage collection after processing
}

// GOOD: Use limits
const runs = [];
for await (const run of client.listRuns({
  projectName: "huge",
  limit: 1000 // Explicit limit
})) {
  runs.push(run);
}

// GOOD: Batch processing with limits
const batchSize = 100;
let batch = [];

for await (const run of client.listRuns({ projectName: "project" })) {
  batch.push(run);

  if (batch.length >= batchSize) {
    await processBatch(batch);
    batch = []; // Clear batch to free memory
  }
}

// Process remaining
if (batch.length > 0) {
  await processBatch(batch);
}

Error Recovery Strategies

Strategy: Circuit Breaker Pattern

Prevent cascading failures by stopping requests after repeated errors.

class CircuitBreaker {
  private failureCount = 0;
  private failureThreshold = 5;
  private resetTimeout = 60000; // 1 minute
  private state: 'closed' | 'open' | 'half-open' = 'closed';
  private lastFailure?: number;

  async execute<T>(operation: () => Promise<T>): Promise<T> {
    if (this.state === 'open') {
      const timeSinceFailure = Date.now() - (this.lastFailure || 0);
      if (timeSinceFailure < this.resetTimeout) {
        throw new Error("Circuit breaker is OPEN - too many failures");
      }
      this.state = 'half-open';
    }

    try {
      const result = await operation();

      // Success - reset if in half-open
      if (this.state === 'half-open') {
        this.state = 'closed';
        this.failureCount = 0;
      }

      return result;
    } catch (error) {
      this.failureCount++;
      this.lastFailure = Date.now();

      // Open circuit if threshold exceeded
      if (this.failureCount >= this.failureThreshold) {
        this.state = 'open';
        console.error(`Circuit breaker opened after ${this.failureCount} failures`);
      }

      throw error;
    }
  }
}

// Usage
const breaker = new CircuitBreaker();
const client = new Client();

async function robustCreateRun(params: any) {
  return await breaker.execute(() => client.createRun(params));
}

Strategy: Fallback to Local Logging

Continue operation with local logging if LangSmith unavailable.

import { Client } from "langsmith";
import * as fs from "fs";

class ResilientTracer {
  private client: Client;
  private fallbackPath: string;
  private langsmithAvailable = true;

  constructor(fallbackPath = "./traces.jsonl") {
    this.client = new Client();
    this.fallbackPath = fallbackPath;
  }

  async createRun(run: any) {
    if (this.langsmithAvailable) {
      try {
        await this.client.createRun(run);
        return;
      } catch (error) {
        console.warn("LangSmith unavailable, falling back to local logging");
        this.langsmithAvailable = false;
        // Fall through to local logging
      }
    }

    // Fallback: log to local file
    fs.appendFileSync(
      this.fallbackPath,
      JSON.stringify(run) + "\n"
    );
  }

  async flush() {
    if (this.langsmithAvailable) {
      await this.client.awaitPendingTraceBatches();
    }
  }
}

Debugging Error Scenarios

Enable Debug Mode

const client = new Client({
  debug: true // Logs all HTTP requests
});

// See full request/response details in console
await client.createRun({...});

Verbose Error Logging

import { Client } from "langsmith";

const client = new Client();

try {
  await client.createRun({...});
} catch (error) {
  console.error("=== LangSmith Error Details ===");
  console.error("Status:", error.status);
  console.error("Message:", error.message);
  console.error("Method:", error.config?.method);
  console.error("URL:", error.config?.url);
  console.error("Data:", JSON.stringify(error.config?.data, null, 2));
  console.error("Response:", error.response?.data);
  console.error("================================");
  throw error;
}

Error Handling Best Practices

✅ Always Handle Expected Errors

// GOOD: Handle known error scenarios
try {
  const dataset = await client.readDataset({ datasetName });
} catch (error) {
  if (error.status === 404) {
    // Expected: create dataset
    await client.createDataset({ datasetName });
  } else if (error.status === 401) {
    // Expected: auth issue
    throw new Error("Invalid API key - check configuration");
  } else {
    // Unexpected: log for debugging
    console.error("Unexpected error:", error);
    throw error;
  }
}

✅ Provide Context in Error Messages

// GOOD: Contextual error messages
try {
  await client.createExample({
    dataset_id: datasetId,
    inputs: exampleInputs,
    outputs: exampleOutputs
  });
} catch (error) {
  throw new Error(
    `Failed to create example in dataset ${datasetId}: ${error.message}`
  );
}

✅ Log Errors Without Exposing Secrets

// BAD: May log API key
console.error("Error with config:", clientConfig);

// GOOD: Sanitize before logging
const safeConfig = {
  ...clientConfig,
  apiKey: clientConfig.apiKey ? "[REDACTED]" : undefined
};
console.error("Error with config:", safeConfig);

✅ Use Type Guards for Error Checking

function isLangSmithError(error: any): error is { status: number; message: string } {
  return typeof error === 'object' && 'status' in error;
}

try {
  await client.createRun({...});
} catch (error) {
  if (isLangSmithError(error)) {
    console.error(`API error ${error.status}:`, error.message);
  } else {
    console.error("Unexpected error:", error);
  }
}

Error Recovery Checklist

When encountering errors, check:

  • API Key: Is LANGCHAIN_API_KEY set and valid?
  • Network: Can you reach api.smith.langchain.com?
  • Project: Does the project exist?
  • Imports: Using correct subpath imports?
  • Flush: Called awaitPendingTraceBatches() before exit?
  • Types: Using correct run_type, data_type values?
  • IDs: Are resource IDs correct and in right workspace?
  • Permissions: Does API key have required permissions?
  • Rate Limits: Are you within rate limits?
  • Batching: Is batch size within limits?
  • Timeouts: Are operations completing within timeout_ms?
  • Validation: Do inputs match expected schema?

Related Documentation

  • Anti-Patterns - Common mistakes to avoid
  • Decision Trees - Choosing the right API
  • Client Configuration - Client setup
  • Quick Reference - Common patterns
  • Troubleshooting - Setup issues