sipeed/picoclaw · error · ErrTemporary

discord send media: %w

Error message

discord send media: %w

What it means

The goroutine performing ChannelMessageSendComplex (multi-file upload) returned an error; it is wrapped as channels.ErrTemporary so the manager retries with exponential backoff. The underlying discordgo error (file too large, missing permission, network) is dropped by the wrap, so the cause is invisible in the returned error.

Source

Thrown at pkg/channels/discord/discord.go:350

			Files:   files,
		})
		if err != nil {
			done <- mediaResult{err: err}
			return
		}
		done <- mediaResult{id: sentMsg.ID}
	}()

	select {
	case r := <-done:
		// Close all file readers
		for _, f := range files {
			if closer, ok := f.Reader.(*os.File); ok {
				closer.Close()
			}
		}
		if r.err != nil {
			return nil, fmt.Errorf("discord send media: %w", channels.ErrTemporary)
		}
		if hasTrackedMsg {
			c.dismissTrackedToolFeedbackMessage(ctx, channelID, trackedMsgID)
		}
		return []string{r.id}, nil
	case <-sendCtx.Done():
		// Close all file readers
		for _, f := range files {
			if closer, ok := f.Reader.(*os.File); ok {
				closer.Close()
			}
		}
		return nil, sendCtx.Err()
	}
}

// EditMessage implements channels.MessageEditor.
func (c *DiscordChannel) EditMessage(ctx context.Context, chatID string, messageID string, content string) error {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Check file sizes against Discord's upload limit and compress/split media before sending
  2. Verify the bot has Send Messages + Attach Files permissions in that specific channel and that the channel still exists
  3. Patch the wrap to keep the cause: fmt.Errorf("discord send media: %w: %w", channels.ErrTemporary, r.err) so diagnosis is possible
  4. For slow networks, raise sendTimeout or stream fewer parts per message

Example fix

// before
if r.err != nil {
    return nil, fmt.Errorf("discord send media: %w", channels.ErrTemporary)
}

// after
if r.err != nil {
    return nil, fmt.Errorf("discord send media: %w: %w", channels.ErrTemporary, r.err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate parts before SendMedia
const discordUploadLimit = 8 << 20 // 8 MiB free tier
for _, part := range msg.Parts {
    if fi, err := os.Stat(path); err == nil && fi.Size() > discordUploadLimit {
        return fmt.Errorf("part %s exceeds discord upload limit", part.Ref)
    }
}

Type guard

func isTemporarySend(err error) bool { return errors.Is(err, channels.ErrTemporary) }

Try / catch

if _, err := ch.SendMedia(ctx, msg); err != nil {
    if errors.Is(err, channels.ErrTemporary) {
        // manager retries with backoff; oversize/permission failures keep failing —
        // shrink media or fix permissions instead of retrying forever
    }
    return err
}

Prevention

When it happens

Trigger: Uploading files over the bot upload limit (8 MiB free tier / 25 MiB boosted servers via multipart), missing ATTACH_FILES or SEND_MESSAGES permission in the target channel, network failure mid-upload within the 10s sendTimeout, invalid/archived channelID.

Common situations: Agent outputs large images/videos, bot permissions changed or bot kicked from the channel, uploads through a slow proxy timing out, sending to a deleted channel.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/99b7957df140a5c4. Report an issue: GitHub.