fix(telegram): avoid wedging callback updates on permanent edit errors

This commit is contained in:
Lucenx9
2026-04-18 15:51:04 +02:00
committed by Peter Steinberger
parent a07b9fc840
commit d8b18f1d96
2 changed files with 68 additions and 1 deletions

View File

@@ -674,6 +674,12 @@ export const registerTelegramHandlers = ({
}
}
const TELEGRAM_PERMANENT_CALLBACK_EDIT_ERROR_RE =
/400:\s*Bad Request:\s*message to edit not found|400:\s*Bad Request:\s*there is no text in the message to edit|MESSAGE_ID_INVALID|message can't be edited/i;
const isPermanentTelegramCallbackEditError = (err: unknown): boolean =>
TELEGRAM_PERMANENT_CALLBACK_EDIT_ERROR_RE.test(String(err));
const resolveTelegramEventAuthorizationContext = async (params: {
chatId: number;
isGroup: boolean;
@@ -1672,10 +1678,15 @@ export const registerTelegramHandlers = ({
messageIdOverride: callback.id,
});
} catch (err) {
runtime.error?.(danger(`callback handler failed: ${String(err)}`));
if (err instanceof TelegramRetryableCallbackError) {
if (isPermanentTelegramCallbackEditError(err.cause)) {
logVerbose(`telegram: swallowing permanent callback edit error: ${String(err.cause)}`);
return;
}
runtime.error?.(danger(`callback handler failed: ${String(err)}`));
throw err.cause;
}
runtime.error?.(danger(`callback handler failed: ${String(err)}`));
}
});

View File

@@ -3328,6 +3328,62 @@ describe("createTelegramBot", () => {
expect(editMessageTextSpy.mock.calls.at(-1)?.[2]).toContain("Commands (2/");
});
it("treats permanent command pagination edit failures as completed updates", async () => {
sequentializeSpy.mockImplementationOnce(
() => async (_ctx: unknown, next: () => Promise<void>) => {
await next();
},
);
const onUpdateId = vi.fn();
createTelegramBot({
token: "tok",
updateOffset: {
lastUpdateId: 776,
onUpdateId,
},
});
const callbackHandler = getOnHandler("callback_query");
const ctx = {
update: { update_id: 777 },
callbackQuery: {
id: "cbq-commands-permanent-edit-1",
data: "commands_page_2:main",
from: { id: 9, first_name: "Ada", username: "ada_bot" },
message: {
chat: { id: 1234, type: "private" },
date: 1736380800,
message_id: 20,
},
},
me: { username: "openclaw_bot" },
getFile: async () => ({ download: async () => new Uint8Array() }),
};
editMessageTextSpy.mockRejectedValueOnce(
new Error("400: Bad Request: message can't be edited"),
);
await expect(
runTelegramMiddlewareChain({
ctx,
finalHandler: callbackHandler,
}),
).resolves.toBeUndefined();
await vi.waitFor(() => {
expect(onUpdateId).toHaveBeenCalledWith(777);
});
await runTelegramMiddlewareChain({
ctx,
finalHandler: callbackHandler,
});
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
});
it("retries command pagination callbacks after a bubbled preflight failure", async () => {
const listSkillCommandsMock = listSkillCommandsForAgents as unknown as ReturnType<typeof vi.fn>;
listSkillCommandsMock.mockClear();