CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-isomorphic-git

A pure JavaScript implementation of git for node and browsers

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

isomorphic-git provides a comprehensive set of error classes for different failure conditions.

Error Classes

Core Errors

/**
 * Base error class for all isomorphic-git errors
 */
class BaseError extends Error {
  name: string;
  code: string;
  data: any;
}

/**
 * Reference or object not found
 */
class NotFoundError extends BaseError {
  constructor(what: string);
}

/**
 * Invalid reference name
 */
class InvalidRefNameError extends BaseError {
  constructor(ref: string);
}

/**
 * Invalid object ID format
 */
class InvalidOidError extends BaseError {
  constructor(value: string);
}

/**
 * Invalid file path
 */
class InvalidFilepathError extends BaseError {
  constructor(filepath: string);
}

/**
 * Unsafe file path (potential security issue)
 */
class UnsafeFilepathError extends BaseError {
  constructor(filepath: string);
}

/**
 * Required parameter missing
 */
class MissingParameterError extends BaseError {
  constructor(parameter: string);
}

/**
 * Required name parameter missing
 */
class MissingNameError extends BaseError {
  constructor();
}

/**
 * Ambiguous reference (multiple matches)
 */
class AmbiguousError extends BaseError {
  constructor(nouns: string[], matches: string[]);
}

/**
 * Object or reference already exists
 */
class AlreadyExistsError extends BaseError {
  constructor(noun: string, where: string, name?: string);
}

/**
 * Internal library error
 */
class InternalError extends BaseError {
  constructor(message: string);
}

Checkout and Merge Errors

/**
 * Checkout would overwrite local changes
 */
class CheckoutConflictError extends BaseError {
  constructor(filepaths: string[]);
}

/**
 * Merge conflict occurred
 */
class MergeConflictError extends BaseError {
  constructor(filepaths: string[]);
}

/**
 * Merge operation not supported for this scenario
 */
class MergeNotSupportedError extends BaseError {
  constructor();
}

/**
 * Repository has unmerged paths
 */
class UnmergedPathsError extends BaseError {
  constructor(filepaths: string[]);
}

/**
 * Fast-forward merge not possible
 */
class FastForwardError extends BaseError {
  constructor();
}

Remote Operation Errors

/**
 * HTTP request error
 */
class HttpError extends BaseError {
  constructor(statusCode: number, statusMessage: string, response: string);
}

/**
 * Git push operation failed
 */
class GitPushError extends BaseError {
  constructor(prettyDetails: string, result: any);
}

/**
 * Push rejected by remote server
 */
class PushRejectedError extends BaseError {
  constructor(reason: string);
}

/**
 * Empty response from server
 */
class EmptyServerResponseError extends BaseError {
  constructor();
}

/**
 * Smart HTTP protocol error
 */
class SmartHttpError extends BaseError {
  constructor(preview: string, response: string);
}

/**
 * Remote capability not supported
 */
class RemoteCapabilityError extends BaseError {
  constructor(capability: string, remote: string);
}

/**
 * Unknown transport protocol
 */
class UnknownTransportError extends BaseError {
  constructor(url: string);
}

/**
 * URL parsing error
 */
class UrlParseError extends BaseError {
  constructor(url: string);
}

/**
 * No refspec configured for push/pull
 */
class NoRefspecError extends BaseError {
  constructor(remote: string);
}

Repository State Errors

/**
 * Required commit not fetched from remote
 */
class CommitNotFetchedError extends BaseError {
  constructor(ref: string, oid: string);
}

/**
 * No commit found (empty repository)
 */
class NoCommitError extends BaseError {
  constructor();
}

/**
 * Multiple .git directories found
 */
class MultipleGitError extends BaseError {
  constructor(gitdirs: string[]);
}

/**
 * Maximum recursion depth reached
 */
class MaxDepthError extends BaseError {
  constructor(depth: number);
}

/**
 * Object type mismatch
 */
class ObjectTypeError extends BaseError {
  constructor(oid: string, actual: string, expected: string);
}

/**
 * Parsing error for Git objects or references
 */
class ParseError extends BaseError {
  constructor(expected: string, actual: string);
}

/**
 * Index reset error
 */
class IndexResetError extends BaseError {
  constructor(filepath: string);
}

User Interaction Errors

/**
 * User canceled the operation
 */
class UserCanceledError extends BaseError {
  constructor();
}

Usage Examples

Basic Error Handling

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  await git.checkout({
    fs,
    dir: "/path/to/repo",
    ref: "nonexistent-branch"
  });
} catch (error) {
  if (error instanceof Errors.NotFoundError) {
    console.log("Branch not found:", error.data);
  } else {
    console.log("Unexpected error:", error.message);
  }
}

Specific Error Handling

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  await git.checkout({
    fs,
    dir: "/path/to/repo",
    ref: "main"
  });
} catch (error) {
  switch (error.constructor) {
    case Errors.CheckoutConflictError:
      console.log("Cannot checkout - would overwrite:", error.data.filepaths);
      // Offer to stash or commit changes
      break;
      
    case Errors.NotFoundError:
      console.log("Branch not found:", error.data);
      // Offer to create branch or list available branches
      break;
      
    case Errors.InvalidRefNameError:
      console.log("Invalid branch name:", error.data.ref);
      break;
      
    default:
      console.log("Checkout failed:", error.message);
  }
}

Network Error Handling

import git, { Errors } from "isomorphic-git";
import http from "isomorphic-git/http/node";
import fs from "fs";

try {
  await git.push({
    fs,
    http,
    dir: "/path/to/repo",
    remote: "origin",
    ref: "main"
  });
} catch (error) {
  if (error instanceof Errors.HttpError) {
    switch (error.data.statusCode) {
      case 401:
        console.log("Authentication required");
        break;
      case 403:
        console.log("Permission denied");
        break;
      case 404:
        console.log("Repository not found");
        break;
      default:
        console.log(`HTTP error ${error.data.statusCode}: ${error.data.statusMessage}`);
    }
  } else if (error instanceof Errors.PushRejectedError) {
    console.log("Push rejected:", error.data.reason);
    console.log("Try pulling latest changes first");
  } else if (error instanceof Errors.GitPushError) {
    console.log("Push failed:", error.data.prettyDetails);
  } else {
    console.log("Push error:", error.message);
  }
}

Merge Conflict Handling

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  const result = await git.merge({
    fs,
    dir: "/path/to/repo",
    theirs: "feature-branch"
  });
  
  if (result.conflicts && result.conflicts.length > 0) {
    console.log("Merge conflicts in:", result.conflicts);
    console.log("Please resolve conflicts and commit");
  } else {
    console.log("Merge completed successfully");
  }
} catch (error) {
  if (error instanceof Errors.MergeConflictError) {
    console.log("Merge conflicts detected in:", error.data.filepaths);
    console.log("Resolve conflicts manually, then:");
    console.log("1. git add <resolved-files>");
    console.log("2. git commit");
  } else if (error instanceof Errors.MergeNotSupportedError) {
    console.log("This type of merge is not supported");
    console.log("Try a different merge strategy");
  } else {
    console.log("Merge failed:", error.message);
  }
}

Clone Error Handling

import git, { Errors } from "isomorphic-git";
import http from "isomorphic-git/http/node";
import fs from "fs";

try {
  await git.clone({
    fs,
    http,
    dir: "/path/to/repo",
    url: "https://github.com/user/repo.git"
  });
} catch (error) {
  if (error instanceof Errors.HttpError) {
    if (error.data.statusCode === 404) {
      console.log("Repository not found or private");
    } else {
      console.log(`Network error: ${error.data.statusCode}`);
    }
  } else if (error instanceof Errors.AlreadyExistsError) {
    console.log("Directory already exists and is not empty");
  } else if (error instanceof Errors.UrlParseError) {
    console.log("Invalid repository URL:", error.data.url);
  } else {
    console.log("Clone failed:", error.message);
  }
}

Configuration Error Handling

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  const userName = await git.getConfig({
    fs,
    dir: "/path/to/repo",
    path: "user.name"
  });
  console.log("User name:", userName);
} catch (error) {
  if (error instanceof Errors.NotFoundError) {
    console.log("Configuration not found - setting default");
    await git.setConfig({
      fs,
      dir: "/path/to/repo",
      path: "user.name",
      value: "Default User"
    });
  } else {
    console.log("Configuration error:", error.message);
  }
}

File System Error Handling

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  await git.add({
    fs,
    dir: "/path/to/repo",
    filepath: "nonexistent/file.txt"
  });
} catch (error) {
  if (error instanceof Errors.NotFoundError) {
    console.log("File not found:", error.data);
  } else if (error instanceof Errors.InvalidFilepathError) {
    console.log("Invalid file path:", error.data.filepath);
  } else if (error instanceof Errors.UnsafeFilepathError) {
    console.log("Unsafe file path detected:", error.data.filepath);
  } else {
    console.log("Add failed:", error.message);
  }
}

Error Information

Most errors include additional data in the data property:

import git, { Errors } from "isomorphic-git";
import fs from "fs";

try {
  // Some operation that fails
  await git.resolveRef({
    fs,
    dir: "/path/to/repo",
    ref: "ambiguous-ref"
  });
} catch (error) {
  console.log("Error name:", error.name);
  console.log("Error code:", error.code);
  console.log("Error message:", error.message);
  console.log("Error data:", error.data);
  console.log("Stack trace:", error.stack);
}

Best Practices

1. Always Handle Expected Errors

// Good: Handle expected error conditions
try {
  await git.checkout({ fs, dir, ref: userInput });
} catch (error) {
  if (error instanceof Errors.NotFoundError) {
    // Handle missing branch gracefully
    console.log(`Branch '${userInput}' not found`);
    return;
  }
  throw error; // Re-throw unexpected errors
}

2. Provide User-Friendly Messages

// Good: Convert technical errors to user-friendly messages
try {
  await git.push({ fs, http, dir, remote: "origin", ref: "main" });
} catch (error) {
  let userMessage;
  
  if (error instanceof Errors.HttpError && error.data.statusCode === 401) {
    userMessage = "Authentication failed. Please check your credentials.";
  } else if (error instanceof Errors.PushRejectedError) {
    userMessage = "Push rejected. Please pull the latest changes first.";
  } else {
    userMessage = `Push failed: ${error.message}`;
  }
  
  console.log(userMessage);
}

3. Log Detailed Error Information

// Good: Log technical details for debugging
try {
  await someGitOperation();
} catch (error) {
  // User-friendly message
  console.log("Operation failed:", getUserFriendlyMessage(error));
  
  // Technical details for logs
  console.error("Technical details:", {
    error: error.name,
    code: error.code,
    data: error.data,
    stack: error.stack
  });
}

docs

advanced-operations.md

branch-management.md

commit-operations.md

configuration.md

error-handling.md

index.md

object-operations.md

reference-management.md

remote-operations.md

repository-operations.md

working-directory.md

tile.json