{"record":{"id":"7394766950fec9f6","repo":"github/copilot-sdk","slug":"github-token-provider-returned-neither-a-token-nor-739476","errorCode":null,"errorMessage":"GitHub token provider returned neither a token nor cancellation","messagePattern":"GitHub token provider returned neither a token nor cancellation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/client.go","lineNumber":2604,"sourceCode":"\tprovider := a.client.gitHubTokenProviders[request.RegistrationID]\n\ta.client.gitHubTokenProvidersMux.RUnlock()\n\tif provider == nil {\n\t\treturn nil, fmt.Errorf(\"unknown GitHub token provider registration ID %q\", request.RegistrationID)\n\t}\n\n\tresult, err := provider(GitHubTokenProviderArgs{\n\t\tHost:      request.Host,\n\t\tSessionID: request.SessionID,\n\t\tReason:    request.Reason,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif result != nil && result.Cancelled {\n\t\treturn &rpc.GitHubTokenAcquireResultCancelled{}, nil\n\t}\n\tif result == nil || result.Token == nil {\n\t\treturn nil, fmt.Errorf(\"GitHub token provider returned neither a token nor cancellation\")\n\t}\n\treturn &rpc.GitHubTokenAcquireResultToken{\n\t\tAccessToken: result.Token.AccessToken,\n\t\tTokenType:   result.Token.TokenType,\n\t\tExpiresIn:   result.Token.ExpiresIn,\n\t}, nil\n}\n\n// gitHubTelemetryAdapter adapts the OnGitHubTelemetry option to the generated\n// rpc.GitHubTelemetryHandler interface.\ntype gitHubTelemetryAdapter struct {\n\tcallback func(notification *rpc.GitHubTelemetryNotification)\n}\n\nfunc (a *gitHubTelemetryAdapter) Event(request *rpc.GitHubTelemetryNotification) error {\n\tdefer func() { recover() }() // Ignore handler panics\n\ta.callback(request)\n\treturn nil","sourceCodeStart":2586,"sourceCodeEnd":2622,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/client.go#L2586-L2622","documentation":"Returned by gitHubTokenAdapter.GetToken when the user-supplied provider function finishes without error but yields a result that is either nil or has a nil Token while not marking Cancelled. The adapter contract requires exactly one of: a token, an explicit cancellation, or an error; anything else is a programming error in the provider.","triggerScenarios":"A registered GitHub token provider callback returns (nil, nil), or returns a GitHubTokenProviderArgs result with Token == nil and Cancelled == false.","commonSituations":"Provider implementation forgets to populate Token after an async fetch; early return path returns nil without setting Cancelled; provider swallows a failure and returns a zero-value struct.","solutions":["Fix the provider callback to always return a non-nil Token, set Cancelled: true, or return a non-nil error.","Audit all early-return paths in the provider for forgotten token assignment.","Wrap the provider to validate its result before registration.","If cancellation is the intended outcome, explicitly set result.Cancelled = true."],"exampleFix":"// before\nfunc(p args) (result, error) {\n    tok := fetchToken(args.Host)\n    return &GitHubTokenProviderResult{}, nil // Token never set\n}\n\n// after\nfunc(p args) (result, error) {\n    tok, err := fetchToken(args.Host)\n    if err != nil { return nil, err }\n    if tok == nil { return &GitHubTokenProviderResult{Cancelled: true}, nil }\n    return &GitHubTokenProviderResult{Token: tok}, nil\n}","handlingStrategy":"validation","validationCode":"func validateTokenResult(r *GitHubTokenProviderResult) error {\n    if r == nil { return errors.New(\"provider returned nil result\") }\n    if !r.Cancelled && r.Token == nil { return errors.New(\"provider returned no token and no cancellation\") }\n    return nil\n}","typeGuard":"func hasTokenOrCancelled(r *GitHubTokenProviderResult) bool {\n    return r != nil && (r.Cancelled || r.Token != nil)\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"neither a token nor cancellation\") {\n    // provider bug; fix callback to return token, Cancelled, or error\n}","preventionTips":["Audit every return path of the provider callback for a token, explicit cancellation, or error.","Wrap providers with a validating decorator before registration.","Never return zero-value result structs from async fetch paths."],"tags":["github","token","callback","contract","go"],"backgroundTag":"internal-invariant-violation","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}