bytebase/bytebase · error

%s

Error message

%s

What it means

Lark's webhook endpoint returned 200 with parseable JSON, but the response Code field is non-zero, indicating Lark rejected the message. The error surfaces Lark's own Message field (e.g. 'key words not found' or rate-limit text). This is a Lark-side business error, not a transport failure.

Source

Thrown at backend/plugin/webhook/lark/lark.go:219

	}

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return errors.Wrapf(err, "failed to read POST webhook response from %s", context.URL)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return errors.Errorf("failed to POST webhook %s, status code: %d, response body: %s", context.URL, resp.StatusCode, b)
	}

	webhookResponse := &WebhookResponse{}
	if err := json.Unmarshal(b, webhookResponse); err != nil {
		return errors.Wrapf(err, "malformed webhook response from %s", context.URL)
	}

	if webhookResponse.Code != 0 {
		return errors.Errorf("%s", webhookResponse.Message)
	}

	return nil
}

func getMessageCard(context webhook.Context) *WebhookCard {
	var markdownBuf strings.Builder

	if context.Description != "" {
		_, _ = fmt.Fprintf(&markdownBuf, "%s\n", context.Description)
	}

	for _, meta := range context.GetMetaList() {
		_, _ = fmt.Fprintf(&markdownBuf, "**%s**: %s\n", meta.Name, meta.Value)
	}

	if context.ActorName != "" {
		_, _ = fmt.Fprintf(&markdownBuf, "**Actor**: %s (%s)\n", context.ActorName, context.ActorEmail)

View on GitHub (pinned to 1870550677)

Solutions

  1. Read the surfaced Message text — it names the exact Lark-side cause.
  2. If the message is 'key words not found', either add the configured keyword to Bytebase's message or remove the keyword requirement in the Lark bot settings.
  3. If the message indicates an invalid sign, re-check the webhook secret/token and ensure server clock sync (NTP).
  4. If rate-limited, add throttling/queueing for webhook deliveries and retry with backoff.
  5. Verify the bot still exists and is enabled in the Lark group; recreate the webhook if revoked.

Example fix

// before: message may not contain the Lark bot keyword
"title": "Pipeline succeeded"
// after: include the configured keyword in the card text
"title": "[Bytebase] Pipeline succeeded"
Defensive patterns

Strategy: validation

Validate before calling

// ensure the configured keyword appears in the outgoing message text
if larkKeyword != "" && !strings.Contains(cardText, larkKeyword) {
    return fmt.Errorf("message must contain Lark bot keyword %q", larkKeyword)
}

Type guard

null

Try / catch

if err := postMessage(...); err != nil {
    msg := strings.TrimPrefix(err.Error(), "")
    switch {
    case strings.Contains(msg, "key words not found"):
        // fix keyword configuration
    case strings.Contains(msg, "sign"):
        // fix secret / clock sync
    default:
        // rate limit or other: retry with backoff
    }
}

Prevention

When it happens

Trigger: postMessage gets Code != 0 in the WebhookResponse — most commonly Lark's 'key words not found' security policy (message must contain a configured keyword), invalid sign (signature mismatch for signature-enabled bots), or exceeding frequency limits.

Common situations: Lark bot configured with a custom keyword but the Bytebase message doesn't contain it; signature verification enabled in Lark but Bytebase signs with a wrong secret or clock drift; sending too many notifications per second (Lark limits ~5/s per bot).

Related errors


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