@@ -24,6 +24,8 @@ var permanentErrorStatuses = []int{
24
24
http .StatusBadRequest , // returned if API mismatch
25
25
http .StatusNotFound , // returned if user doesn't have permission or agent doesn't exist
26
26
http .StatusInternalServerError , // returned if database is not reachable,
27
+ http .StatusUnauthorized , // returned if user is not authenticated
28
+ http .StatusForbidden , // returned if user is not authorized
27
29
}
28
30
29
31
type WebsocketDialer struct {
@@ -39,6 +41,24 @@ type WebsocketDialer struct {
39
41
isFirst bool
40
42
}
41
43
44
+ // checkResumeTokenFailure checks if the parsed error indicates a resume token failure
45
+ // and updates the resumeTokenFailed flag accordingly. Returns true if a resume token
46
+ // failure was detected.
47
+ func (w * WebsocketDialer ) checkResumeTokenFailure (ctx context.Context , sdkErr * codersdk.Error ) bool {
48
+ if sdkErr == nil {
49
+ return false
50
+ }
51
+
52
+ for _ , v := range sdkErr .Validations {
53
+ if v .Field == "resume_token" {
54
+ w .logger .Warn (ctx , "failed to dial tailnet v2+ API: server replied invalid resume token; unsetting for next connection attempt" )
55
+ w .resumeTokenFailed = true
56
+ return true
57
+ }
58
+ }
59
+ return false
60
+ }
61
+
42
62
type WebsocketDialerOption func (* WebsocketDialer )
43
63
44
64
func WithWorkspaceUpdates (req * proto.WorkspaceUpdatesRequest ) WebsocketDialerOption {
@@ -82,9 +102,14 @@ func (w *WebsocketDialer) Dial(ctx context.Context, r tailnet.ResumeTokenControl
82
102
if w .isFirst {
83
103
if res != nil && slices .Contains (permanentErrorStatuses , res .StatusCode ) {
84
104
err = codersdk .ReadBodyAsError (res )
85
- // A bit more human-readable help in the case the API version was rejected
86
105
var sdkErr * codersdk.Error
87
106
if xerrors .As (err , & sdkErr ) {
107
+ // Check for resume token failure first
108
+ if w .checkResumeTokenFailure (ctx , sdkErr ) {
109
+ return tailnet.ControlProtocolClients {}, err
110
+ }
111
+
112
+ // A bit more human-readable help in the case the API version was rejected
88
113
if sdkErr .Message == AgentAPIMismatchMessage &&
89
114
sdkErr .StatusCode () == http .StatusBadRequest {
90
115
sdkErr .Helper = fmt .Sprintf (
@@ -107,13 +132,8 @@ func (w *WebsocketDialer) Dial(ctx context.Context, r tailnet.ResumeTokenControl
107
132
bodyErr := codersdk .ReadBodyAsError (res )
108
133
var sdkErr * codersdk.Error
109
134
if xerrors .As (bodyErr , & sdkErr ) {
110
- for _ , v := range sdkErr .Validations {
111
- if v .Field == "resume_token" {
112
- // Unset the resume token for the next attempt
113
- w .logger .Warn (ctx , "failed to dial tailnet v2+ API: server replied invalid resume token; unsetting for next connection attempt" )
114
- w .resumeTokenFailed = true
115
- return tailnet.ControlProtocolClients {}, err
116
- }
135
+ if w .checkResumeTokenFailure (ctx , sdkErr ) {
136
+ return tailnet.ControlProtocolClients {}, err
117
137
}
118
138
}
119
139
if ! errors .Is (err , context .Canceled ) {
0 commit comments