Skip to content

Treat RichText strings as JSON only when they parse to an object - #2635

Merged
Badiboy merged 1 commit into
eternnoir:masterfrom
cristianchiriac:fix/richtext-json-looking-text
Oct 17, 2026
Merged

Badiboy merged 1 commit into
eternnoir:masterfrom
cristianchiriac:fix/richtext-json-looking-text

Conversation

@cristianchiriac

Copy link
Copy Markdown
Contributor

Description

Fixes #2634.

RichText.de_json() treated a plain-text string as JSON whenever it looked like a JSON object or array and parsed. A superscript footnote mark like "[56]" (common in Wikipedia-sourced rich messages) parses to the list [56]. It then went on to check_json() and obj.pop('type', None) on that list, and polling failed with:

pop expected at most 1 argument, got 2

Now only a string that parses to a JSON object is handled as a serialized RichText. Anything else ("[56]", "[]", numbers, "null", invalid JSON) is returned as plain text, as the docs describe ("can be either a String for plain text…"). A JSON array string never worked before either: it hit the same pop on a list. Real arrays of rich text arrive as lists and still go through the existing list branch.

Describe your tests

New test_json_richtext_plain_text_that_looks_like_json:

  • the issue's case: a URL whose text is a superscript "[56]" deserializes to RichTextUrl → RichTextSuperscript with text "[56]";
  • "[56]", "[]", "{}x", "123", "null" and '["a", "b"]' passed directly come back unchanged.

It fails before the change and passes after it. pytest tests/test_types.py: 266 passed.

Python version: 3.12

OS: Windows 11

Checklist:

  • I added/edited example on new feature/change (if exists) (not applicable)
  • My changes won't break backward compatibility
  • I made changes both for sync and async (shared telebot/types.py)

Plain text that happens to parse as JSON, like a "[56]" superscript
footnote mark, was turned into a list and then crashed with
'pop expected at most 1 argument, got 2'. Fixes eternnoir#2634
@Badiboy

Badiboy commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

I assumed that

https://core.telegram.org/bots/api#richtext

RichText
This object represents a rich formatted text. Currently, it can be either a String for plain text, an Array of [RichText]...(https://core.telegram.org/bots/api#richtext), or any of the following types:

means array in data... Looks you are right: "Array of [RichText]" in fact is also encoded as json...

@Badiboy

Badiboy commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Mmm. I remebered the reason of having this condition.

[{"x": 1}, {"y": 2}]

this is also a valid JSON. Thus due to the problem arized by Telegram who gives us "...it can be either a String for plain text,..." the way to detect if string is JSON or not is quite unsolvable...

Thus I supposed that
Array of [RichText](https://core.telegram.org/bots/api#richtext)
will be represented exactly as

[{richtext},{richtext},{richtext}]

in json string.

I cannot proof this. If this suggestion is wrong - we can apply your fix. If not - we definitely cannot.

@cristianchiriac

Copy link
Copy Markdown
Contributor Author

An Array of RichText doesn't reach de_json as a string. The whole update is one JSON document, parsed once, and every caller passes obj['text'] (or obj['credit']) from that already-parsed dict. So an array arrives as a Python list and goes through the list branch, and a nested array like {"type": "bold", "text": ["a", {"type": "italic", "text": "b"}]} still gives ['a', RichTextItalic] with this change. When the value is a str, Telegram sent a JSON string, which is plain text.

A string like '[{"type": "bold", "text": "x"}]' was also never handled on master: it passes the json.loads check, then check_json returns a list and obj.pop('type', None) fails with the same pop expected at most 1 argument error as "[56]" (checked on current master). So the change doesn't drop any case that worked before.

@Badiboy

Badiboy commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Okay, looks you are right. I'll check a bit more and will proceed.

Thank you.

@Badiboy
Badiboy merged commit 25c04fd into eternnoir:master Oct 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Critical bug: obj.pop in RichText.de_json() fails as it got a list instead of a dictionary

2 participants