Repository: google/go-github (go)

Issue:
ErrorResponse.Error() method can panic if err.Response.Request is nil
First of all thank you so much for this sdk. It is so useful for writing tools/bots using this.

I am trying to implement a new tool using this sdk, and ran into a problem where printing the ErrorResponse is causing 'nil pointer dereference' error.

on trying to debug this, it seems like in following code `r.Response.Request` is nil and therefore resulting in the error:

```
func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v %+v",
		r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
		r.Response.StatusCode, r.Message, r.Errors)
}

```

would it be ok if we added a nil check in this function?

FWIW, I was trying to use CreatePullRequest API with a PAT which didn't had enough permissions and therefore getting a `403 forbidden` error.

the json representation of the error is attached for reference:

<details>
  <summary>JSON representation of ErrorResponse</summary>
  
```
{
  "resp": {
    "Status": "403 Forbidden",
    "StatusCode": 403,
    "Proto": "HTTP/1.1",
    "ProtoMajor": 1,
    "ProtoMinor": 1,
    "Header": {
      "Access-Control-Allow-Origin": [
        "*"
      ],
      "Access-Control-Expose-Headers": [
        "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset"
      ],
      "Content-Security-Policy": [
        "default-src none"
      ],
      "Content-Type": [
        "application/json; charset=utf-8"
      ],
      "Date": [
        "Mon, 23 Oct 2023 15:50:56 GMT"
      ],
      "Github-Authentication-Token-Expiration": [
        "2024-10-22 00:00:00 +0530"
      ],
      "Referrer-Policy": [
        "origin-when-cross-origin, strict-origin-when-cross-origin"
      ],
      "Server": [
        "GitHub.com"
      ],
      "Strict-Transport-Security": [
        "max-age=31536000; includeSubdomains; preload"
      ],
      "Transfer-Encoding": [
        "chunked"
      ],
      "Vary": [
        "Accept-Encoding, Accept, X-Requested-With"
      ],
      "X-Accepted-Github-Permissions": [
        "pull_requests=write"
      ],
      "X-Content-Type-Options": [
        "nosniff"
      ],
      "X-Frame-Options": [
        "deny"
      ],
      "X-Github-Api-Version-Selected": [
        "2022-11-28"
      ],
      "X-Github-Media-Type": [
        "github.v3; format=json"
      ],
      "X-Github-Request-Id": [
        "C56A:146E27:5D915D:6C0EFE:65369660"
      ],
      "X-Ratelimit-Limit": [
        "5000"
      ],
      "X-Ratelimit-Remaining": [
        "4976"
      ],
      "X-Ratelimit-Reset": [
        "1698079299"
      ],
      "X-Ratelimit-Resource": [
        "core"
      ],
      "X-Ratelimit-Used": [
        "24"
      ],
      "X-Xss-Protection": [
        "0"
      ]
    },
    "Body": {
      "Reader": {}
    },
    "ContentLength": 147,
    "TransferEncoding": null,
    "Close": false,
    "Uncompressed": false,
    "Trailer": null,
    "Request": null,
    "TLS": null
  },
  "message": "Resource not accessible by personal access token",
  "errors": null,
  "documentation_url": "https://docs.github.com/rest/pulls/pulls#create-a-pull-request"
}e
```
</details>



Pull request:
Add nil check in ErrorResponse.Error method
fixes #2970 

Patch:
diff --git a/github/github.go b/github/github.go
index edd86ab2..834aa86b 100644
--- a/github/github.go
+++ b/github/github.go
@@ -1017,9 +1017,17 @@ type ErrorBlock struct {
 }
 
 func (r *ErrorResponse) Error() string {
-	return fmt.Sprintf("%v %v: %d %v %+v",
-		r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
-		r.Response.StatusCode, r.Message, r.Errors)
+	if r.Response != nil && r.Response.Request != nil {
+		return fmt.Sprintf("%v %v: %d %v %+v",
+			r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
+			r.Response.StatusCode, r.Message, r.Errors)
+	}
+
+	if r.Response != nil {
+		return fmt.Sprintf("%d %v %+v", r.Response.StatusCode, r.Message, r.Errors)
+	}
+
+	return fmt.Sprintf("%v %+v", r.Message, r.Errors)
 }
 
 // Is returns whether the provided error equals this error.


Test patch:
diff --git a/github/github_test.go b/github/github_test.go
index 90e95b03..b994496c 100644
--- a/github/github_test.go
+++ b/github/github_test.go
@@ -2097,6 +2097,19 @@ func TestErrorResponse_Error(t *testing.T) {
 	if err.Error() == "" {
 		t.Errorf("Expected non-empty ErrorResponse.Error()")
 	}
+
+	//dont panic if request is nil
+	res = &http.Response{}
+	err = ErrorResponse{Message: "m", Response: res}
+	if err.Error() == "" {
+		t.Errorf("Expected non-empty ErrorResponse.Error()")
+	}
+
+	//dont panic if response is nil
+	err = ErrorResponse{Message: "m"}
+	if err.Error() == "" {
+		t.Errorf("Expected non-empty ErrorResponse.Error()")
+	}
 }
 
 func TestError_Error(t *testing.T) {