sipeed/picoclaw · error
feishu edit api error (code=%d msg=%s)
Error message
feishu edit api error (code=%d msg=%s)
What it means
FeishuChannel.EditMessage's Patch call completed and the response parsed, but resp.Success() is false: Feishu returned a non-zero business code. Common codes: 99991661/99991663 (invalid or expired tenant_access_token), 230002 (no permission / bot not in chat), invalid message_id, or the message is not editable (e.g. it was a plain-text fallback message, which cannot be card-patched). invalidateTokenOnAuthError(resp.Code) already ran for auth-class codes.
Source
Thrown at pkg/channels/feishu/feishu_64.go:263
// Uses Message.Patch to update an interactive card message.
func (c *FeishuChannel) EditMessage(ctx context.Context, chatID, messageID, content string) error {
cardContent, err := buildMarkdownCard(content)
if err != nil {
return fmt.Errorf("feishu edit: card build failed: %w", err)
}
req := larkim.NewPatchMessageReqBuilder().
MessageId(messageID).
Body(larkim.NewPatchMessageReqBodyBuilder().Content(cardContent).Build()).
Build()
resp, err := c.client.Im.V1.Message.Patch(ctx, req)
if err != nil {
return fmt.Errorf("feishu edit: %w", err)
}
if !resp.Success() {
c.invalidateTokenOnAuthError(resp.Code)
return fmt.Errorf("feishu edit api error (code=%d msg=%s)", resp.Code, resp.Msg)
}
return nil
}
// DeleteMessage implements channels.MessageDeleter.
func (c *FeishuChannel) DeleteMessage(ctx context.Context, chatID, messageID string) error {
deleteFn := c.deleteMessageFn
if deleteFn == nil {
deleteFn = c.deleteMessageAPI
}
return deleteFn(ctx, chatID, messageID)
}
func (c *FeishuChannel) deleteMessageAPI(ctx context.Context, chatID, messageID string) error {
req := larkim.NewDeleteMessageReqBuilder().
MessageId(messageID).
Build()
View on GitHub (pinned to 49183d7e8d)
Solutions
- Read the code in the message: 99991661/99991663 means auth - let the token refresh (invalidateTokenOnAuthError already triggered) or recheck app credentials
- 230002/permission codes: confirm the bot is still in the chat and has im:message scope
- Invalid message_id or non-editable message: stop patching and delete + resend a fresh message instead
- Do not blind-retry permanent business errors; surface them to the pipeline
Example fix
// before
if err := ch.EditMessage(ctx, chatID, msgID, content); err != nil {
retry() // wrong: business codes are usually permanent
}
// after
err := ch.EditMessage(ctx, chatID, msgID, content)
if code, ok := feishuAPICode(err); ok {
switch code {
case 99991661, 99991663: // auth: token already invalidated, next call re-auths
retrySoon()
default:
resendAsNewMessage(ctx, chatID, content) // patch impossible
}
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
var feishuCodeRe = regexp.MustCompile(`api error \(code=(\d+)`)
func feishuErrorCode(err error) (int, bool) {
if err == nil { return 0, false }
m := feishuCodeRe.FindStringSubmatch(err.Error())
if m == nil { return 0, false }
n, _ := strconv.Atoi(m[1])
return n, true
} Try / catch
if err := ch.EditMessage(ctx, chatID, msgID, content); err != nil {
if code, ok := feishuErrorCode(err); ok {
switch code {
case 99991661, 99991663: // auth: token invalidation already triggered
time.Sleep(time.Second); retryOnce()
default: // permission / bad message_id: permanent
resendAsNewMessage(ctx, chatID, content)
}
}
} Prevention
- Do not retry non-auth business codes; they are deterministic
- Refresh-then-retry only 99991661/99991663-class codes
- Verify bot membership and im:message scopes before edit-heavy flows
- Log code+msg verbatim; they map 1:1 to Feishu's documented error catalog
When it happens
Trigger: Message.Patch responds with code!=0: editing a deleted/nonexistent message_id, editing a message the bot lacks permission for, expired tenant token, or patching a non-card message type.
Common situations: Editing a placeholder that already fell back to plain text; bot removed from the chat between send and edit; token invalidated by concurrent restarts or credential rotation; message_id from a different tenant/app.
Related errors
- feishu delete api error (code=%d msg=%s)
- feishu edit: %w
- bot info api error (code=%d)
- feishu edit: card build failed: %w
- feishu delete: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/ba47eafc3a8b3b40.
Report an issue: GitHub.