Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita68ab3a

Browse files
authored
fix: NPE during error reporting (#186)
The try/catch block raised NPE in the `notify` if another exception wasraised after the context containing the URL was reset - so that means anerror in the onConnect handler. In addition, some of the reset stepswere moved after onConnect to make sure they execute only if onConnectcallback is successful.Because of the fault in how the steps were arranged, the originalexception was never logged instead a misleading NPE was treated by thecoroutine's exception handler.
1 parent22f53f6 commita68ab3a

File tree

6 files changed

+106
-53
lines changed

6 files changed

+106
-53
lines changed

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
- improved diagnose support
88

9+
###Fixed
10+
11+
- NPE during error reporting
12+
913
##0.6.3 - 2025-08-25
1014

1115
###Added

‎src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,6 @@ class CoderRemoteProvider(
409409
context.logger.info("Displaying${client.url} in the UI")
410410
pollJob= poll(client, cli)
411411
context.logger.info("Workspace poll job created with reference$pollJob")
412-
context.envPageManager.showPluginEnvironmentsPage()
413412
}
414413

415414
privatefun MutableStateFlow<LoadableState<List<CoderRemoteEnvironment>>>.showLoadingMessage() {

‎src/main/kotlin/com/coder/toolbox/views/CoderCliSetupWizardPage.kt‎

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,19 @@ package com.coder.toolbox.views
33
importcom.coder.toolbox.CoderToolboxContext
44
importcom.coder.toolbox.cli.CoderCLIManager
55
importcom.coder.toolbox.sdk.CoderRestClient
6-
importcom.coder.toolbox.sdk.ex.APIResponseException
76
importcom.coder.toolbox.views.state.CoderCliSetupWizardState
87
importcom.coder.toolbox.views.state.WizardStep
98
importcom.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
109
importcom.jetbrains.toolbox.api.ui.actions.RunnableActionDescription
1110
importcom.jetbrains.toolbox.api.ui.components.UiField
12-
importkotlinx.coroutines.CoroutineName
1311
importkotlinx.coroutines.flow.MutableStateFlow
12+
importkotlinx.coroutines.flow.StateFlow
1413
importkotlinx.coroutines.flow.update
15-
importkotlinx.coroutines.launch
16-
importjava.util.UUID
1714

1815
classCoderCliSetupWizardPage(
1916
privatevalcontext:CoderToolboxContext,
2017
privatevalsettingsPage:CoderSettingsPage,
21-
privatevalvisibilityState:MutableStateFlow<ProviderVisibilityState>,
18+
visibilityState:StateFlow<ProviderVisibilityState>,
2219
initialAutoSetup:Boolean =false,
2320
jumpToMainPageOnError:Boolean =false,
2421
onConnect:suspend (
@@ -31,33 +28,28 @@ class CoderCliSetupWizardPage(
3128
context.ui.showUiPage(settingsPage)
3229
})
3330

34-
privateval deploymentUrlStep=DeploymentUrlStep(context,this::notify)
31+
privateval deploymentUrlStep=DeploymentUrlStep(context,visibilityState)
3532
privateval tokenStep=TokenStep(context)
3633
privateval connectStep=ConnectStep(
3734
context,
3835
shouldAutoLogin= shouldAutoSetup,
3936
jumpToMainPageOnError,
40-
this::notify,
37+
visibilityState,
4138
this::displaySteps,
4239
onConnect
4340
)
41+
privateval errorReporter=ErrorReporter.create(context, visibilityState,this.javaClass)
4442

4543
/**
4644
* Fields for this page, displayed in order.
4745
*/
4846
overrideval fields:MutableStateFlow<List<UiField>>=MutableStateFlow(emptyList())
4947
overrideval actionButtons:MutableStateFlow<List<RunnableActionDescription>>=MutableStateFlow(emptyList())
5048

51-
privateval errorBuffer= mutableListOf<Throwable>()
5249

5350
overridefunbeforeShow() {
5451
displaySteps()
55-
if (errorBuffer.isNotEmpty()&& visibilityState.value.applicationVisible) {
56-
errorBuffer.forEach {
57-
showError(it)
58-
}
59-
errorBuffer.clear()
60-
}
52+
errorReporter.flush()
6153
}
6254

6355
privatefundisplaySteps() {
@@ -124,30 +116,5 @@ class CoderCliSetupWizardPage(
124116
/**
125117
* Show an error as a popup on this page.
126118
*/
127-
funnotify(logPrefix:String,ex:Throwable) {
128-
context.logger.error(ex, logPrefix)
129-
if (!visibilityState.value.applicationVisible) {
130-
context.logger.debug("Toolbox is not yet visible, scheduling error to be displayed later")
131-
errorBuffer.add(ex)
132-
return
133-
}
134-
showError(ex)
135-
}
136-
137-
privatefunshowError(ex:Throwable) {
138-
val textError=if (exisAPIResponseException) {
139-
if (!ex.reason.isNullOrBlank()) {
140-
ex.reason
141-
}else ex.message
142-
}else ex.message
143-
144-
context.cs.launch(CoroutineName("Coder Setup Visual Error Reporting")) {
145-
context.ui.showSnackbar(
146-
UUID.randomUUID().toString(),
147-
context.i18n.ptrl("Error encountered while setting up Coder"),
148-
context.i18n.pnotr(textError?:""),
149-
context.i18n.ptrl("Dismiss")
150-
)
151-
}
152-
}
119+
funnotify(message:String,ex:Throwable)= errorReporter.report(message, ex)
153120
}

‎src/main/kotlin/com/coder/toolbox/views/ConnectStep.kt‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.coder.toolbox.plugin.PluginManager
77
importcom.coder.toolbox.sdk.CoderRestClient
88
importcom.coder.toolbox.views.state.CoderCliSetupContext
99
importcom.coder.toolbox.views.state.CoderCliSetupWizardState
10+
importcom.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
1011
importcom.jetbrains.toolbox.api.ui.components.LabelField
1112
importcom.jetbrains.toolbox.api.ui.components.RowGroup
1213
importcom.jetbrains.toolbox.api.ui.components.ValidationErrorField
@@ -27,24 +28,23 @@ class ConnectStep(
2728
privatevalcontext:CoderToolboxContext,
2829
privatevalshouldAutoLogin:StateFlow<Boolean>,
2930
privatevaljumpToMainPageOnError:Boolean,
30-
privatevalnotify: (String,Throwable)->Unit,
31+
visibilityState:StateFlow<ProviderVisibilityState>,
3132
privatevalrefreshWizard: ()->Unit,
32-
privatevalonConnect:suspend (
33-
client:CoderRestClient,
34-
cli:CoderCLIManager,
35-
)->Unit,
33+
privatevalonConnect:suspend (client:CoderRestClient, cli:CoderCLIManager)->Unit,
3634
) : WizardStep {
3735
privatevar signInJob:Job?=null
3836

3937
privateval statusField=LabelField(context.i18n.pnotr(""))
4038
privateval errorField=ValidationErrorField(context.i18n.pnotr(""))
39+
privateval errorReporter=ErrorReporter.create(context, visibilityState,this.javaClass)
4140

4241
overrideval panel:RowGroup=RowGroup(
4342
RowGroup.RowField(statusField),
4443
RowGroup.RowField(errorField)
4544
)
4645

4746
overridefunonVisible() {
47+
errorReporter.flush()
4848
errorField.textState.update {
4949
context.i18n.pnotr("")
5050
}
@@ -73,6 +73,9 @@ class ConnectStep(
7373
errorField.textState.update { context.i18n.ptrl("Token is required") }
7474
return
7575
}
76+
// Capture the host name early for error reporting
77+
val hostName=CoderCliSetupContext.url!!.host
78+
7679
signInJob?.cancel()
7780
signInJob= context.cs.launch(CoroutineName("Http and CLI Setup")) {
7881
try {
@@ -100,21 +103,23 @@ class ConnectStep(
100103
yield()
101104
cli.login(client.token!!)
102105
}
103-
logAndReportProgress("Successfully configured${CoderCliSetupContext.url!!.host}...")
106+
logAndReportProgress("Successfully configured${hostName}...")
104107
// allows interleaving with the back/cancel action
105108
yield()
106-
CoderCliSetupContext.reset()
107-
CoderCliSetupWizardState.goToFirstStep()
108109
context.logger.info("Connection setup done, initializing the workspace poller...")
109110
onConnect(client, cli)
111+
112+
CoderCliSetupContext.reset()
113+
CoderCliSetupWizardState.goToFirstStep()
114+
context.envPageManager.showPluginEnvironmentsPage()
110115
}catch (ex:CancellationException) {
111116
if (ex.message!=USER_HIT_THE_BACK_BUTTON) {
112-
notify("Connection to${CoderCliSetupContext.url!!.host} was configured", ex)
117+
errorReporter.report("Connection to$hostName was configured", ex)
113118
handleNavigation()
114119
refreshWizard()
115120
}
116121
}catch (ex:Exception) {
117-
notify("Failed to configure${CoderCliSetupContext.url!!.host}", ex)
122+
errorReporter.report("Failed to configure$hostName", ex)
118123
handleNavigation()
119124
refreshWizard()
120125
}

‎src/main/kotlin/com/coder/toolbox/views/DeploymentUrlStep.kt‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import com.coder.toolbox.util.toURL
66
importcom.coder.toolbox.util.validateStrictWebUrl
77
importcom.coder.toolbox.views.state.CoderCliSetupContext
88
importcom.coder.toolbox.views.state.CoderCliSetupWizardState
9+
importcom.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
910
importcom.jetbrains.toolbox.api.ui.components.CheckboxField
1011
importcom.jetbrains.toolbox.api.ui.components.LabelField
1112
importcom.jetbrains.toolbox.api.ui.components.LabelStyleType
1213
importcom.jetbrains.toolbox.api.ui.components.RowGroup
1314
importcom.jetbrains.toolbox.api.ui.components.TextField
1415
importcom.jetbrains.toolbox.api.ui.components.TextType
1516
importcom.jetbrains.toolbox.api.ui.components.ValidationErrorField
17+
importkotlinx.coroutines.flow.StateFlow
1618
importkotlinx.coroutines.flow.update
1719
importjava.net.MalformedURLException
1820
importjava.net.URL
@@ -25,9 +27,11 @@ import java.net.URL
2527
*/
2628
classDeploymentUrlStep(
2729
privatevalcontext:CoderToolboxContext,
28-
privatevalnotify: (String,Throwable)->Unit
30+
visibilityState:StateFlow<ProviderVisibilityState>,
2931
) :
3032
WizardStep {
33+
privateval errorReporter=ErrorReporter.create(context, visibilityState,this.javaClass)
34+
3135
privateval urlField=TextField(context.i18n.ptrl("Deployment URL"),"",TextType.General)
3236
privateval emptyLine=LabelField(context.i18n.pnotr(""),LabelStyleType.Normal)
3337

@@ -66,6 +70,7 @@ class DeploymentUrlStep(
6670
signatureFallbackStrategyField.checkedState.update {
6771
context.settingsStore.fallbackOnCoderForSignatures.isAllowed()
6872
}
73+
errorReporter.flush()
6974
}
7075

7176
overridefunonNext():Boolean {
@@ -78,7 +83,7 @@ class DeploymentUrlStep(
7883
try {
7984
CoderCliSetupContext.url= validateRawUrl(url)
8085
}catch (e:MalformedURLException) {
81-
notify("URL is invalid", e)
86+
errorReporter.report("URL is invalid", e)
8287
returnfalse
8388
}
8489
if (context.settingsStore.requireTokenAuth) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
packagecom.coder.toolbox.views
2+
3+
importcom.coder.toolbox.CoderToolboxContext
4+
importcom.coder.toolbox.sdk.ex.APIResponseException
5+
importcom.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
6+
importkotlinx.coroutines.flow.StateFlow
7+
importkotlinx.coroutines.launch
8+
importjava.util.UUID
9+
10+
sealedclassErrorReporter {
11+
12+
/**
13+
* Logs and show errors as popups.
14+
*/
15+
abstractfunreport(message:String,ex:Throwable)
16+
17+
/**
18+
* Processes any buffered errors when the application becomes visible.
19+
*/
20+
abstractfunflush()
21+
22+
companionobject {
23+
funcreate(
24+
context:CoderToolboxContext,
25+
visibilityState:StateFlow<ProviderVisibilityState>,
26+
callerClass:Class<*>
27+
):ErrorReporter=ErrorReporterImpl(context, visibilityState, callerClass)
28+
}
29+
}
30+
31+
privateclassErrorReporterImpl(
32+
privatevalcontext:CoderToolboxContext,
33+
privatevalvisibilityState:StateFlow<ProviderVisibilityState>,
34+
privatevalcallerClass:Class<*>
35+
) : ErrorReporter() {
36+
privateval errorBuffer= mutableListOf<Throwable>()
37+
38+
overridefunreport(message:String,ex:Throwable) {
39+
context.logger.error(ex,"[${callerClass.simpleName}]$message")
40+
if (!visibilityState.value.applicationVisible) {
41+
context.logger.debug("Toolbox is not yet visible, scheduling error to be displayed later")
42+
errorBuffer.add(ex)
43+
return
44+
}
45+
showError(ex)
46+
}
47+
48+
privatefunshowError(ex:Throwable) {
49+
val textError=if (exisAPIResponseException) {
50+
if (!ex.reason.isNullOrBlank()) {
51+
ex.reason
52+
}else ex.message
53+
}else ex.message?: ex.toString()
54+
context.cs.launch {
55+
context.ui.showSnackbar(
56+
UUID.randomUUID().toString(),
57+
context.i18n.ptrl("Error encountered while setting up Coder"),
58+
context.i18n.pnotr(textError?:""),
59+
context.i18n.ptrl("Dismiss")
60+
)
61+
}
62+
}
63+
64+
65+
overridefunflush() {
66+
if (errorBuffer.isNotEmpty()&& visibilityState.value.applicationVisible) {
67+
errorBuffer.forEach {
68+
showError(it)
69+
}
70+
errorBuffer.clear()
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp