Skip to content

Commit ce0478f

Browse files
committed
fix: handle activateProviderProfile errors gracefully during mode switch
When switching modes, if activateProviderProfile fails (e.g. due to corrupted profile data or proxy provider configuration issues), the error would propagate up and leave the mode in an inconsistent state - the mode was already updated in memory and global state, but the API configuration was not switched. This wraps the activateProviderProfile call in handleModeSwitch with a try-catch so the mode switch completes gracefully, falling back to the current API configuration. The error is logged for diagnostics. Closes #12098
1 parent 7adbfec commit ce0478f

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

src/core/webview/ClineProvider.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,19 @@ export class ClineProvider
14551455
const hasActualSettings = !!fullProfile.apiProvider
14561456

14571457
if (hasActualSettings) {
1458-
await this.activateProviderProfile({ name: profile.name })
1458+
try {
1459+
await this.activateProviderProfile({ name: profile.name })
1460+
} catch (error) {
1461+
// If profile activation fails (e.g. corrupted profile data,
1462+
// proxy provider configuration issues), log the error but
1463+
// allow the mode switch to complete gracefully. The task will
1464+
// continue with the current API configuration.
1465+
this.log(
1466+
`Failed to activate provider profile "${profile.name}" during mode switch to "${newMode}": ${
1467+
error instanceof Error ? error.message : String(error)
1468+
}`,
1469+
)
1470+
}
14591471
} else {
14601472
// The task will continue with the current/default configuration.
14611473
}

src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,64 @@ describe("ClineProvider - Sticky Mode", () => {
10441044

10451045
consoleErrorSpy.mockRestore()
10461046
})
1047+
1048+
it("should complete mode switch gracefully when activateProviderProfile fails", async () => {
1049+
await provider.resolveWebviewView(mockWebviewView)
1050+
1051+
const mockTask = {
1052+
taskId: "test-task-id",
1053+
_taskMode: "code",
1054+
emit: vi.fn(),
1055+
saveClineMessages: vi.fn(),
1056+
clineMessages: [],
1057+
apiConversationHistory: [],
1058+
updateApiConfiguration: vi.fn(),
1059+
}
1060+
1061+
await provider.addClineToStack(mockTask as any)
1062+
1063+
// Mock getGlobalState to return task history
1064+
vi.spyOn(provider as any, "getGlobalState").mockReturnValue([
1065+
{
1066+
id: mockTask.taskId,
1067+
ts: Date.now(),
1068+
task: "Test task",
1069+
number: 1,
1070+
tokensIn: 0,
1071+
tokensOut: 0,
1072+
cacheWrites: 0,
1073+
cacheReads: 0,
1074+
totalCost: 0,
1075+
},
1076+
])
1077+
1078+
// Mock updateTaskHistory to succeed
1079+
vi.spyOn(provider, "updateTaskHistory").mockImplementation(() => Promise.resolve([]))
1080+
1081+
// Mock providerSettingsManager to return a saved config for the target mode
1082+
const mockConfigId = "test-config-id"
1083+
vi.spyOn(provider.providerSettingsManager, "getModeConfigId").mockResolvedValue(mockConfigId)
1084+
vi.spyOn(provider.providerSettingsManager, "listConfig").mockResolvedValue([
1085+
{ id: mockConfigId, name: "test-profile" },
1086+
])
1087+
vi.spyOn(provider.providerSettingsManager, "getProfile").mockResolvedValue({
1088+
id: mockConfigId,
1089+
name: "test-profile",
1090+
apiProvider: "openai" as any,
1091+
})
1092+
1093+
// Mock activateProviderProfile to throw (simulating a proxy provider configuration issue)
1094+
vi.spyOn(provider, "activateProviderProfile").mockRejectedValue(
1095+
new Error("Failed to activate profile: connection error"),
1096+
)
1097+
1098+
// The mode switch should complete without throwing
1099+
await expect(provider.handleModeSwitch("architect")).resolves.not.toThrow()
1100+
1101+
// The mode should still be updated despite profile activation failure
1102+
expect(mockTask._taskMode).toBe("architect")
1103+
expect(vi.mocked(mockContext.globalState.update)).toHaveBeenCalledWith("mode", "architect")
1104+
})
10471105
})
10481106

10491107
describe("Multiple tasks switching modes simultaneously", () => {

0 commit comments

Comments
 (0)