From 530c62128bf878136a1558a7711c133cda999324 Mon Sep 17 00:00:00 2001 From: EzekialSA Date: Tue, 9 Dec 2025 21:12:22 -0600 Subject: [PATCH 1/2] fix: handle service messages and unsupported message types - Add UnsupportedMessageTypeError to handle MessageService, MessageEmpty, etc. - Update GetSingleMessage to return specific error instead of generic 'invalid message' - Add error handling in download iterator to skip system messages gracefully - System messages include 'user joined', 'message pinned', etc. which aren't downloadable --- app/dl/iter.go | 11 +++++++++++ core/util/tutil/tutil.go | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/dl/iter.go b/app/dl/iter.go index 8bf536159..d1814368f 100644 --- a/app/dl/iter.go +++ b/app/dl/iter.go @@ -171,6 +171,17 @@ func (i *iter) process(ctx context.Context) (ret bool, skip bool) { } message, err := tutil.GetSingleMessage(ctx, i.pool.Default(ctx), peer, msg) if err != nil { + // Check if message is an unsupported type (MessageService, MessageEmpty, etc.) + var unsupportedErr *tutil.UnsupportedMessageTypeError + if errors.As(err, &unsupportedErr) { + logctx.From(ctx).Warn("Skipping system message", + zap.Int64("peer_id", unsupportedErr.PeerID), + zap.Int("message_id", unsupportedErr.MessageID), + zap.String("message_type", unsupportedErr.MessageType), + ) + i.logicalPos++ // increment logical position to skip this message + return false, true + } i.err = errors.Wrap(err, "resolve message") return false, false } diff --git a/core/util/tutil/tutil.go b/core/util/tutil/tutil.go index 76f92851a..abb23e0d4 100644 --- a/core/util/tutil/tutil.go +++ b/core/util/tutil/tutil.go @@ -171,6 +171,16 @@ func FileExists(msg tg.MessageClass) bool { } } +type UnsupportedMessageTypeError struct { + PeerID int64 + MessageID int + MessageType string +} + +func (e *UnsupportedMessageTypeError) Error() string { + return fmt.Sprintf("message %d/%d has unsupported type: %s (system message, not downloadable)", e.PeerID, e.MessageID, e.MessageType) +} + func GetSingleMessage(ctx context.Context, c *tg.Client, peer tg.InputPeerClass, msg int) (*tg.Message, error) { it := query.Messages(c). GetHistory(peer).OffsetID(msg + 1). @@ -182,7 +192,13 @@ func GetSingleMessage(ctx context.Context, c *tg.Client, peer tg.InputPeerClass, m, ok := it.Value().Msg.(*tg.Message) if !ok { - return nil, errors.Errorf("invalid message %d", msg) + // Message exists but is not a regular message (likely MessageService, MessageEmpty, etc.) + // These are system messages like "user joined", "message pinned", etc. and should be skipped + return nil, &UnsupportedMessageTypeError{ + PeerID: GetInputPeerID(peer), + MessageID: msg, + MessageType: fmt.Sprintf("%T", it.Value().Msg), + } } // check if message is deleted From ac9a66d597c3b1a995668e5bb7e3ca13b773121d Mon Sep 17 00:00:00 2001 From: EzekialSA Date: Tue, 9 Dec 2025 21:29:13 -0600 Subject: [PATCH 2/2] feat: add console output for skipped messages - Add DeletedMessageError type for better error handling - Show yellow warning in console when skipping system/deleted messages - Both log to file and display to user during download --- app/dl/iter.go | 15 +++++++++++++++ core/util/tutil/tutil.go | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/dl/iter.go b/app/dl/iter.go index d1814368f..4fa740378 100644 --- a/app/dl/iter.go +++ b/app/dl/iter.go @@ -13,6 +13,7 @@ import ( "text/template" "time" + "github.com/fatih/color" "github.com/go-faster/errors" "github.com/gotd/td/telegram/peers" "github.com/gotd/td/tg" @@ -174,6 +175,8 @@ func (i *iter) process(ctx context.Context) (ret bool, skip bool) { // Check if message is an unsupported type (MessageService, MessageEmpty, etc.) var unsupportedErr *tutil.UnsupportedMessageTypeError if errors.As(err, &unsupportedErr) { + color.Yellow("Skipping system message: %d/%d (%s)", + unsupportedErr.PeerID, unsupportedErr.MessageID, unsupportedErr.MessageType) logctx.From(ctx).Warn("Skipping system message", zap.Int64("peer_id", unsupportedErr.PeerID), zap.Int("message_id", unsupportedErr.MessageID), @@ -182,6 +185,18 @@ func (i *iter) process(ctx context.Context) (ret bool, skip bool) { i.logicalPos++ // increment logical position to skip this message return false, true } + // Check if message is deleted + var deletedErr *tutil.DeletedMessageError + if errors.As(err, &deletedErr) { + color.Yellow("Skipping deleted message: %d/%d", + deletedErr.PeerID, deletedErr.MessageID) + logctx.From(ctx).Warn("Skipping deleted message", + zap.Int64("peer_id", deletedErr.PeerID), + zap.Int("message_id", deletedErr.MessageID), + ) + i.logicalPos++ // increment logical position to skip this message + return false, true + } i.err = errors.Wrap(err, "resolve message") return false, false } diff --git a/core/util/tutil/tutil.go b/core/util/tutil/tutil.go index abb23e0d4..e6a55fd50 100644 --- a/core/util/tutil/tutil.go +++ b/core/util/tutil/tutil.go @@ -171,6 +171,15 @@ func FileExists(msg tg.MessageClass) bool { } } +type DeletedMessageError struct { + PeerID int64 + MessageID int +} + +func (e *DeletedMessageError) Error() string { + return fmt.Sprintf("message %d/%d may be deleted", e.PeerID, e.MessageID) +} + type UnsupportedMessageTypeError struct { PeerID int64 MessageID int @@ -203,7 +212,10 @@ func GetSingleMessage(ctx context.Context, c *tg.Client, peer tg.InputPeerClass, // check if message is deleted if m.GetID() != msg { - return nil, errors.Errorf("the message %d/%d may be deleted", GetInputPeerID(peer), msg) + return nil, &DeletedMessageError{ + PeerID: GetInputPeerID(peer), + MessageID: msg, + } } return m, nil