bytebase/bytebase · error

failed to POST Google Chat webhook, status code: %d, respons

Error message

failed to POST Google Chat webhook, status code: %d, response body: %s

What it means

This error is returned when the Google Chat webhook endpoint replies with a non-2xx HTTP status code. postMessage reads the whole response body and embeds both the status code and the raw body in the message, so the caller can see exactly what Google Chat rejected and why. It is a server-side rejection of the POST, not a transport failure.

Source

Thrown at backend/plugin/webhook/googlechat/googlechat.go:216

		return errors.New("failed to construct Google Chat webhook POST request")
	}

	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	client := &http.Client{
		Timeout: webhook.Timeout,
	}
	resp, err := client.Do(req)
	if err != nil {
		return errors.New("failed to POST Google Chat webhook")
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return errors.New("failed to read Google Chat webhook response")
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return errors.Errorf("failed to POST Google Chat webhook, status code: %d, response body: %s", resp.StatusCode, b)
	}

	return nil
}

func marshal(post MessagePayload) ([]byte, error) {
	var body bytes.Buffer
	encoder := json.NewEncoder(&body)
	encoder.SetEscapeHTML(false)
	if err := encoder.Encode(post); err != nil {
		return nil, err
	}
	return bytes.TrimSpace(body.Bytes()), nil
}

View on GitHub (pinned to 1870550677)

Solutions

  1. Read the status code and body in the error to identify the rejection reason (404 = bad URL, 403 = revoked webhook, 429 = rate limited).
  2. Re-create the Google Chat space webhook in the Chat UI and update the stored webhook URL, since deleted/rotated webhooks return 403/404.
  3. Verify the configured URL matches the full https://chat.googleapis.com/v1/spaces/.../messages?key=...&token=... form.
  4. If 429, reduce notification frequency or batch events before retrying with backoff.

Example fix

// before
URL: "https://chat.googleapis.com/v1/spaces/OLD_SPACE_ID/messages?key=oldKey"
// returns 404 not found
// after
URL: "https://chat.googleapis.com/v1/spaces/AAAA-newSpace/messages?key=newKey&token=newToken"
// returns 200 OK
Defensive patterns

Strategy: retry

Validate before calling

// Before saving the webhook URL, ping it:
func validateChatWebhook(u string) error {
	req, _ := http.NewRequest(http.MethodPost, u, bytes.NewBufferString(`{"text":"test"}`))
	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	resp, err := http.DefaultClient.Do(req)
	if err != nil { return err }
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 { return fmt.Errorf("webhook returned %d", resp.StatusCode) }
	return nil
}

Type guard

func isWebhookStatusError(err error) (int, string, bool) {
	var n, msg string
	_, scanErr := fmt.Sscanf(err.Error(), "failed to POST Google Chat webhook, status code: %d", new(int))
	_ = n; _ = msg; _ = scanErr
	return 0, "", strings.Contains(err.Error(), "status code:")
}

Try / catch

if err := googlechat.Post(ctx); err != nil {
	var status int
	if n, _ := fmt.Sscanf(err.Error(), "failed to POST Google Chat webhook, status code: %d", &status); n == 1 {
		switch {
		case status == 429:
			time.Sleep(backoff); retry()
		case status == 404 || status == 403:
			alertOwnerToRecreateWebhook(err)
		}
	}
	return err
}

Prevention

When it happens

Trigger: postMessage POSTs the marshaled message to context.URL via client.Do, gets a response with StatusCode < 200 or >= 300, and formats the status plus response body into this error.

Common situations: The webhook URL was revoked or mistyped (404), the Google Chat space webhook was deleted (403/404), an invalid or truncated webhook URL/key is configured, or Google rate-limits the space (429).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/72dac730e340362f. Report an issue: GitHub.