Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/browser/components/ChatInput/useCreationWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { KNOWN_MODELS } from "@/common/constants/knownModels";
import { getModelCapabilities } from "@/common/utils/ai/modelCapabilities";
import { normalizeModelInput } from "@/browser/utils/models/normalizeModelInput";
import { resolveDevcontainerSelection } from "@/browser/utils/devcontainerSelection";
import { getErrorMessage } from "@/common/utils/errors";

export type CreationSendResult = { success: true } | { success: false; error?: SendMessageError };

Expand Down Expand Up @@ -545,7 +546,7 @@ export function useCreationWorkspace({

return { success: true };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
const errorMessage = getErrorMessage(err);
setToast({
id: Date.now().toString(),
type: "error",
Expand Down
5 changes: 2 additions & 3 deletions src/browser/components/hooks/useGitBranchDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type GitBranchHeader,
} from "@/common/utils/git/parseGitLog";
import { useAPI } from "@/browser/contexts/API";
import { getErrorMessage } from "@/common/utils/errors";

const GitBranchDataSchema = z.object({
showBranch: z.string(),
Expand Down Expand Up @@ -274,9 +275,7 @@ printf '__MUX_BRANCH_DATA__BEGIN_DIRTY_FILES__\\n%s\\n__MUX_BRANCH_DATA__END_DIR
timestamp: Date.now(),
};
} catch (error) {
setErrorMessage(
`Failed to fetch branch info: ${error instanceof Error ? error.message : String(error)}`
);
setErrorMessage(`Failed to fetch branch info: ${getErrorMessage(error)}`);
setCommits(null);
} finally {
setIsLoading(false);
Expand Down
3 changes: 2 additions & 1 deletion src/browser/hooks/useMuxGatewayAccountStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CUSTOM_EVENTS, createCustomEvent } from "@/common/constants/events";
import { GATEWAY_CONFIGURED_KEY } from "@/common/constants/storage";
import { MUX_GATEWAY_SESSION_EXPIRED_MESSAGE } from "@/common/constants/muxGatewayOAuth";
import { formatCostWithDollar } from "@/common/utils/tokens/usageAggregator";
import { getErrorMessage } from "@/common/utils/errors";

export interface MuxGatewayAccountStatus {
remaining_microdollars: number;
Expand Down Expand Up @@ -51,7 +52,7 @@ export function useMuxGatewayAccountStatus() {

setError(result.error);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const message = getErrorMessage(err);
setError(message);
} finally {
setIsLoading(false);
Expand Down
5 changes: 3 additions & 2 deletions src/browser/hooks/useVoiceInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { matchesKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds";
import { stopKeyboardPropagation } from "@/browser/utils/events";
import type { APIClient } from "@/browser/contexts/API";
import { trackVoiceTranscription } from "@/common/telemetry";
import { getErrorMessage } from "@/common/utils/errors";

export type VoiceInputState = "idle" | "requesting" | "recording" | "transcribing";

Expand Down Expand Up @@ -187,7 +188,7 @@ export function useVoiceInput(options: UseVoiceInputOptions): UseVoiceInputResul
setTimeout(() => callbacksRef.current.onSend?.(), 0);
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = getErrorMessage(err);
callbacksRef.current.onError?.(`Transcription failed: ${msg}`);
trackVoiceTranscription(audioDurationSecs, false);
} finally {
Expand Down Expand Up @@ -265,7 +266,7 @@ export function useVoiceInput(options: UseVoiceInputOptions): UseVoiceInputResul
recordingStartTimeRef.current = Date.now();
setState("recording");
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = getErrorMessage(err);
const isPermissionDenied = msg.includes("Permission denied") || msg.includes("NotAllowed");

callbacksRef.current.onError?.(
Expand Down
3 changes: 2 additions & 1 deletion src/browser/hooks/useWorkspaceName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getWorkspaceNameStateKey } from "@/common/constants/storage";
import { useGateway, formatAsGatewayModel } from "./useGatewayModels";
import { getKnownModel } from "@/common/constants/knownModels";
import { validateWorkspaceName } from "@/common/utils/validation/workspaceValidation";
import { getErrorMessage } from "@/common/utils/errors";

/** Small/fast models preferred for name generation */
const PREFERRED_MODELS = [getKnownModel("HAIKU").id, getKnownModel("GPT_MINI").id];
Expand Down Expand Up @@ -272,7 +273,7 @@ export function useWorkspaceName(options: UseWorkspaceNameOptions): UseWorkspace
if (requestId !== requestIdRef.current) {
return null;
}
const errorMsg = err instanceof Error ? err.message : String(err);
const errorMsg = getErrorMessage(err);
setError(errorMsg);
safeResolve(null);
return null;
Expand Down
3 changes: 2 additions & 1 deletion src/browser/terminal/TerminalSessionRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import type { RouterClient } from "@orpc/server";
import type { AppRouter } from "@/node/orpc/router";
import { getErrorMessage } from "@/common/utils/errors";

type APIClient = RouterClient<AppRouter>;

Expand Down Expand Up @@ -349,7 +350,7 @@ export class TerminalSessionRouter {
} catch (err) {
if (!signal.aborted) {
// Ignore "session not found" errors for exit stream
const errMsg = err instanceof Error ? err.message : String(err);
const errMsg = getErrorMessage(err);
if (!errMsg.includes("isOpen") && !errMsg.includes("undefined")) {
console.error(`[TerminalRouter] Exit stream error for ${sessionId}:`, err);
}
Expand Down
5 changes: 3 additions & 2 deletions src/cli/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import { runFullInit } from "@/node/runtime/runtimeFactory";
import { execSync } from "child_process";
import { getParseOptions } from "./argv";
import { EXPERIMENT_IDS } from "@/common/constants/experiments";
import { getErrorMessage } from "@/common/utils/errors";

// Display labels for CLI help (OFF, LOW, MED, HIGH, MAX)
const THINKING_LABELS_LIST = Object.values(THINKING_DISPLAY_LABELS).join(", ");
Expand Down Expand Up @@ -530,7 +531,7 @@ async function main(): Promise<number> {
initLogger,
});
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage = getErrorMessage(error);
initLogger.logStderr(`Initialization failed: ${errorMessage}`);
initLogger.logComplete(-1);
initResult = { success: false, error: errorMessage };
Expand Down Expand Up @@ -1111,6 +1112,6 @@ main()
})
.catch((error) => {
clearInterval(keepAliveInterval);
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
console.error(`Error: ${getErrorMessage(error)}`);
process.exit(1);
});
5 changes: 3 additions & 2 deletions src/desktop/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Enable source map support for better error stack traces in production
import "source-map-support/register";
import { getErrorMessage } from "@/common/utils/errors";

// Fix PATH on macOS when launched from Finder (not terminal).
// GUI apps inherit minimal PATH from launchd, missing Homebrew tools like git-lfs.
Expand Down Expand Up @@ -109,7 +110,7 @@ if (process.env.MUX_DEBUG_START_TIME === "1") {
process.on("uncaughtException", (error: unknown) => {
console.error("Uncaught Exception:", error);

const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
const stack = error instanceof Error ? error.stack : undefined;

console.error("Stack:", stack);
Expand All @@ -128,7 +129,7 @@ process.on("unhandledRejection", (reason, promise) => {
console.error("Reason:", reason);

if (app.isPackaged) {
const message = reason instanceof Error ? reason.message : String(reason);
const message = getErrorMessage(reason);
const stack = reason instanceof Error ? reason.stack : undefined;
dialog.showErrorBox(
"Unhandled Promise Rejection",
Expand Down
7 changes: 4 additions & 3 deletions src/node/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { RuntimeConfig } from "@/common/types/runtime";
import { execAsync } from "@/node/utils/disposableExec";
import { createRuntime } from "./runtime/runtimeFactory";
import { log } from "./services/log";
import { getErrorMessage } from "@/common/utils/errors";

/**
* Remove stale .git/index.lock file if it exists and is old.
Expand Down Expand Up @@ -187,7 +188,7 @@ export async function createWorktree(

return { success: true, path: workspacePath };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return { success: false, error: message };
}
}
Expand Down Expand Up @@ -233,7 +234,7 @@ export async function removeWorktree(
await proc.result;
return { success: true };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return { success: false, error: message };
}
}
Expand All @@ -247,7 +248,7 @@ export async function pruneWorktrees(projectPath: string): Promise<WorktreeResul
await proc.result;
return { success: true };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return { success: false, error: message };
}
}
17 changes: 9 additions & 8 deletions src/node/orpc/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
readSubagentTranscriptArtifactsFile,
type SubagentTranscriptArtifactIndexEntry,
} from "@/node/services/subagentTranscriptArtifacts";
import { getErrorMessage } from "@/common/utils/errors";

/**
* Resolves runtime and discovery path for agent operations.
Expand Down Expand Up @@ -154,7 +155,7 @@ async function readChatJsonlAllowMissing(params: {
} catch (parseError) {
log.warn(
`Skipping malformed JSON at line ${i + 1} in ${params.logLabel}:`,
parseError instanceof Error ? parseError.message : String(parseError),
getErrorMessage(parseError),
"\nLine content:",
lines[i].substring(0, 100) + (lines[i].length > 100 ? "..." : "")
);
Expand Down Expand Up @@ -184,7 +185,7 @@ async function readPartialJsonBestEffort(partialPath: string): Promise<MuxMessag
// Never fail transcript viewing because partial.json is corrupted.
log.warn("Failed to read partial.json for transcript", {
partialPath,
error: error instanceof Error ? error.message : String(error),
error: getErrorMessage(error),
});
return null;
}
Expand Down Expand Up @@ -1059,7 +1060,7 @@ export const router = (authToken?: string) => {
},
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return Err(`Mux Gateway balance request failed: ${message}`);
}

Expand Down Expand Up @@ -1094,7 +1095,7 @@ export const router = (authToken?: string) => {
try {
json = await response.json();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return Err(`Mux Gateway balance response was not valid JSON: ${message}`);
}

Expand Down Expand Up @@ -1315,7 +1316,7 @@ export const router = (authToken?: string) => {

return Ok(undefined);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return Err(message);
}
}),
Expand Down Expand Up @@ -2549,7 +2550,7 @@ export const router = (authToken?: string) => {
log.warn("workspace.getSubagentTranscript: descendant check failed", {
requestingWorkspaceId,
taskId,
error: error instanceof Error ? error.message : String(error),
error: getErrorMessage(error),
});
}
}
Expand Down Expand Up @@ -3248,7 +3249,7 @@ export const router = (authToken?: string) => {
await context.sessionTimingService.clearTimingFile(input.workspaceId);
return { success: true, data: undefined };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return { success: false, error: message };
}
}),
Expand Down Expand Up @@ -3288,7 +3289,7 @@ export const router = (authToken?: string) => {
);
return { success: true, data: undefined };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return { success: false, error: message };
}
}),
Expand Down
3 changes: 2 additions & 1 deletion src/node/orpc/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { VERSION } from "@/version";
import { formatOrpcError } from "@/node/orpc/formatOrpcError";
import { log } from "@/node/services/log";
import { attachStreamErrorHandler, isIgnorableStreamError } from "@/node/utils/streamErrors";
import { getErrorMessage } from "@/common/utils/errors";

type AliveWebSocket = WebSocket & { isAlive?: boolean };

Expand Down Expand Up @@ -755,7 +756,7 @@ export async function createOrpcServer({
return;
}

const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
const code =
error && typeof error === "object" && "code" in error && typeof error.code === "string"
? error.code
Expand Down
15 changes: 8 additions & 7 deletions src/node/runtime/CoderSSHRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { log } from "@/node/services/log";
import { execBuffered } from "@/node/utils/runtime/helpers";
import { expandTildeForSSH } from "./tildeExpansion";
import * as path from "path";
import { getErrorMessage } from "@/common/utils/errors";

export interface CoderSSHRuntimeConfig extends SSHRuntimeConfig {
/** Coder-specific configuration */
Expand Down Expand Up @@ -333,7 +334,7 @@ export class CoderSSHRuntime extends SSHRuntime {
emitStatus("ready");
return { ready: true };
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
const errorMsg = getErrorMessage(error);

emitStatus("error");

Expand Down Expand Up @@ -445,7 +446,7 @@ export class CoderSSHRuntime extends SSHRuntime {
if (!coder.existingWorkspace) {
await this.coderService.disposeProvisioningSession(workspaceName);
}
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return Err(
`Failed to read Coder deployment SSH config. ` +
`Make sure you're logged in with the Coder CLI. ` +
Expand Down Expand Up @@ -571,7 +572,7 @@ export class CoderSSHRuntime extends SSHRuntime {
deletedPath: this.getWorkspacePath(projectPath, workspaceName),
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
log.error("Failed to delete stopped Coder workspace", {
coderWorkspaceName,
error: message,
Expand Down Expand Up @@ -603,7 +604,7 @@ export class CoderSSHRuntime extends SSHRuntime {
log.debug(`Deleting Coder workspace "${coderWorkspaceName}"`);
await this.coderService.deleteWorkspace(coderWorkspaceName);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
log.error("Failed to delete Coder workspace", {
coderWorkspaceName,
error: message,
Expand Down Expand Up @@ -700,7 +701,7 @@ export class CoderSSHRuntime extends SSHRuntime {
initLogger.logStdout(line);
}
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
const errorMsg = getErrorMessage(error);
log.error("Failed to create Coder workspace", { error, config: this.coderConfig });
initLogger.logStderr(`Failed to create Coder workspace: ${errorMsg}`);
throw new Error(`Failed to create Coder workspace: ${errorMsg}`);
Expand Down Expand Up @@ -746,7 +747,7 @@ export class CoderSSHRuntime extends SSHRuntime {
initLogger.logStdout(line);
}
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
const errorMsg = getErrorMessage(error);
log.error("Failed waiting for Coder workspace", { error, config: this.coderConfig });
initLogger.logStderr(`Failed connecting to Coder workspace: ${errorMsg}`);
throw new Error(`Failed connecting to Coder workspace: ${errorMsg}`);
Expand All @@ -758,7 +759,7 @@ export class CoderSSHRuntime extends SSHRuntime {
try {
await this.coderService.ensureSSHConfig();
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
const errorMsg = getErrorMessage(error);
log.error("Failed to configure SSH for Coder", { error });
initLogger.logStderr(`Failed to configure SSH: ${errorMsg}`);
throw new Error(`Failed to configure SSH for Coder: ${errorMsg}`);
Expand Down
2 changes: 1 addition & 1 deletion src/node/runtime/DevcontainerRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export class DevcontainerRuntime extends LocalBaseRuntime {
} else {
controller.error(
new RuntimeError(
`Failed to read file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,
`Failed to read file ${filePath}: ${getErrorMessage(err)}`,
"file_io",
err instanceof Error ? err : undefined
)
Expand Down
Loading
Loading