fix: handle ignored io.ReadAll errors across codebase

io.ReadAll errors were silently discarded with `body, _ := io.ReadAll(...)`,
which could cause empty or partial data to be used for JSON unmarshaling
or error messages. This adds proper error checks for all instances.
This commit is contained in:
Yasuhiro Matsumoto
2026-03-05 20:56:38 +09:00
parent 74b5af9e53
commit 943385105f
9 changed files with 61 additions and 15 deletions
@@ -335,7 +335,11 @@ func (s *appState) testModel(model *picoclawconfig.ModelConfig) {
s.showMessage("Test OK", resp.Status)
return
}
body, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
body, err := io.ReadAll(io.LimitReader(resp.Body, 2048))
if err != nil {
s.showMessage("Test failed", fmt.Sprintf("failed to read response: %v", err))
return
}
s.showMessage(
"Test failed",
fmt.Sprintf("%s: %s", resp.Status, strings.TrimSpace(string(body))),
@@ -297,7 +297,10 @@ func fetchGoogleUserEmail(accessToken string) (string, error) {
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("reading userinfo response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("userinfo request failed: %s", string(body))
}
+4 -1
View File
@@ -177,7 +177,10 @@ func fetchGoogleUserEmail(accessToken string) (string, error) {
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("reading userinfo response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("userinfo request failed: %s", string(body))
}
+20 -5
View File
@@ -212,7 +212,10 @@ func RequestDeviceCode(cfg OAuthProviderConfig) (*DeviceCodeInfo, error) {
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading device code response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("device code request failed: %s", string(body))
}
@@ -300,7 +303,10 @@ func LoginDeviceCode(cfg OAuthProviderConfig) (*AuthCredential, error) {
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading device code response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("device code request failed: %s", string(body))
}
@@ -360,7 +366,10 @@ func pollDeviceCode(cfg OAuthProviderConfig, deviceAuthID, userCode string) (*Au
return nil, fmt.Errorf("pending")
}
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading device token response: %w", err)
}
var tokenResp struct {
AuthorizationCode string `json:"authorization_code"`
@@ -401,7 +410,10 @@ func RefreshAccessToken(cred *AuthCredential, cfg OAuthProviderConfig) (*AuthCre
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading token refresh response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("token refresh failed: %s", string(body))
}
@@ -494,7 +506,10 @@ func ExchangeCodeForTokens(cfg OAuthProviderConfig, code, codeVerifier, redirect
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading token exchange response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("token exchange failed: %s", string(body))
}
+4 -1
View File
@@ -654,7 +654,10 @@ func (c *LINEChannel) callAPI(ctx context.Context, endpoint string, payload any)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading LINE API error response: %w", err)
}
return channels.ClassifySendError(resp.StatusCode, fmt.Errorf("LINE API error: %s", string(respBody)))
}
+4 -1
View File
@@ -793,7 +793,10 @@ func (c *WeComAIBotChannel) sendViaResponseURL(responseURL, content string) erro
return nil
}
respBody, _ := io.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading response_url body: %w: %w", channels.ErrTemporary, err)
}
switch {
case resp.StatusCode == http.StatusTooManyRequests:
return fmt.Errorf("response_url rate limited (%d): %s: %w",
+8 -2
View File
@@ -321,7 +321,10 @@ func (c *WeComAppChannel) uploadMedia(ctx context.Context, accessToken, mediaTyp
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("reading wecom upload error response: %w", err)
}
return "", channels.ClassifySendError(resp.StatusCode, fmt.Errorf("wecom upload error: %s", string(respBody)))
}
@@ -371,7 +374,10 @@ func (c *WeComAppChannel) sendWeComMessage(ctx context.Context, accessToken stri
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading wecom_app error response: %w", err)
}
return channels.ClassifySendError(resp.StatusCode, fmt.Errorf("wecom_app API error: %s", string(respBody)))
}
+4 -1
View File
@@ -453,7 +453,10 @@ func (c *WeComBotChannel) sendWebhookReply(ctx context.Context, userID, content
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("reading webhook error response: %w", err)
}
return channels.ClassifySendError(resp.StatusCode, fmt.Errorf("webhook API error: %s", string(body)))
}
+8 -2
View File
@@ -640,7 +640,10 @@ func FetchAntigravityProjectID(accessToken string) (string, error) {
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("reading loadCodeAssist response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("loadCodeAssist failed: %s", string(body))
}
@@ -681,7 +684,10 @@ func FetchAntigravityModels(accessToken, projectID string) ([]AntigravityModelIn
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading fetchAvailableModels response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf(
"fetchAvailableModels failed (HTTP %d): %s",