chenhg5/cc-connect · error

sendAudio fallback failed: %w

Error message

sendAudio fallback failed: %w

What it means

This is the fallback half of the joined error returned when both SendVoice and the SendAudio fallback fail while sending a voice/audio message. It wraps the error from p.sendAudio, the fallback path used when voice sending is unsupported or fails. Its presence means Telegram also rejected the audio variant of the message.

Source

Thrown at platform/telegram/telegram.go:1218

	default:
		converted, err := telegramConvertAudioToOpus(ctx, audio, sendFormat)
		if err != nil {
			return fmt.Errorf("telegram: SendAudio: convert %s to opus: %w", sendFormat, err)
		}
		sendData = converted
		sendFormat = "opus"
	}

	if err := p.sendVoice(ctx, rc, sendData, sendFormat); err != nil {
		if sendFormat == "mp3" || sendFormat == "m4a" {
			if fallbackErr := p.sendAudio(ctx, rc, sendData, sendFormat); fallbackErr == nil {
				return nil
			} else {
				return fmt.Errorf(
					"telegram: SendAudio: %w",
					errors.Join(
						fmt.Errorf("sendVoice failed: %w", err),
						fmt.Errorf("sendAudio fallback failed: %w", fallbackErr),
					),
				)
			}
		}
		return fmt.Errorf("telegram: SendAudio: sendVoice: %w", err)
	}
	return nil
}

func (p *Platform) sendVoice(ctx context.Context, rc replyContext, audio []byte, format string) error {
	bot, err := p.connectedBot("send voice")
	if err != nil {
		return err
	}
	params := &tgbot.SendVoiceParams{
		ChatID:          rc.chatID,
		MessageThreadID: rc.threadID,
		Voice:           &models.InputFileUpload{Filename: "tts_audio." + telegramAudioFileExt(format), Data: bytes.NewReader(audio)},

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the wrapped fallbackErr text for the Bot API's specific rejection reason.
  2. Convert the audio to a standard MP3/M4A and resend via sendAudio, or OGG/Opus for voice.
  3. Handle HTTP 429 retry_after from the Bot API by waiting and retrying.
  4. Check bot chat permissions and file size (50 MB bot limit).

Example fix

// before: ignoring which leg failed
return err
// after: branch on the joined causes
if strings.Contains(err.Error(), "sendAudio fallback failed") { /* audio-specific handling */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if len(audio) == 0 { return errors.New("empty audio payload") }

Try / catch

if err := send(); err != nil {
    var apiErr *tgbot.Error
    if errors.As(err, &apiErr) && apiErr.Code == 429 {
        time.Sleep(time.Duration(apiErr.RetryAfter) * time.Second)
    }
}

Prevention

When it happens

Trigger: After sendVoice fails, p.sendAudio(ctx, rc, sendData, sendFormat) is invoked and returns a non-nil error; the code then returns fmt.Errorf("telegram: SendAudio: %w", errors.Join(voiceErr, audioFallbackErr)).

Common situations: Audio file in a codec/container Telegram's sendAudio rejects (e.g. malformed MP3); caption or duration fields out of range; expired or wrong file_id; bot rate-limited (429).

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/cd0b58cf65a9352f. Report an issue: GitHub.