-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Problem (one or two sentences)
This report covers two related but independent issues in ClineProvider.ts error handling:
- Unguarded
error.messageaccess (5 locations) — runtime safety - Contradictory non-null assertion in
cancelTask()(1 location) — logic contradiction
These can be addressed in separate commits if preferred.
Several catch blocks in ClineProvider.ts access error.message directly without narrowing the caught value. If a non-Error is thrown (string, object, null), this causes secondary TypeErrors or blank error dialogs instead of useful error reporting. Additionally, cancelTask() uses this.getCurrentTask()! === undefined which is internally contradictory (non-null assertion followed by an undefined check).
Context (who is affected and when)
Affects any user when an API call, task abort, or marketplace fetch throws a non-Error value (e.g., a string or plain object). This can happen with third-party API providers, network failures, or unexpected runtime conditions. The user sees a blank error dialog or a "Cannot read properties of undefined (reading 'message')" error instead of the actual failure reason.
Note: This is separate from the unsafe full error-object serialization issue; this report is about runtime safety and correctness of error handling.
Reproduction steps
-
Environment: Any OS, Roo Code v3.47.3, any API provider.
-
Unguarded
.messageaccess in catch blocks (search pattern: catch blocks usingerror.messagewhere the caught value is untyped/unknown):performPreparationTasks(~line 449):vscode.window.showErrorMessage(error.message)removeClineFromStack(~line 473):${e.message}createTaskWithHistoryItem(~line 1006):${e.message}fetchMarketplaceData(~line 1892):errors: [error.message]resumeTask(~line 3019):${error.message}
-
If any of these paths receives a thrown string/plain object (or
null) instead of anErrorinstance,.messagemay be undefined, producing a blank/misleading log or a secondary TypeError. -
Separately,
cancelTask()(~line 2967) usesthis.getCurrentTask()! === undefined(non-null assertion immediately compared to undefined), which is logically contradictory and can be refactored into a clean nullish check.
Expected result
Caught values are narrowed before .message access (for example: err instanceof Error ? err.message : String(err)), and cancelTask() uses a single const current = this.getCurrentTask() check without non-null assertions.
Actual result
Direct .message access on a non-Error thrown value can produce secondary TypeErrors or blank error messages, obscuring the original failure. this.getCurrentTask()! === undefined is internally contradictory and should be simplified.
Variations tried (optional)
The pattern error instanceof Error ? error.message : String(error) is already used in other parts of the same file, confirming it is the established convention. The unguarded locations were likely missed during earlier refactors.
App Version
v3.47.3
API Provider (optional)
None
Model Used (optional)
N/A
Roo Code Task Links (optional)
No response
Relevant logs or errors (optional)
Search pattern for affected locations: error.message in catch blocks where the caught value is untyped/unknown
Search pattern for non-null assertion: this.getCurrentTask()! === undefined
Affected file: src/core/webview/ClineProvider.ts