Skip to content

panic in format text: slice bounds out of range when thread has no replies in time range #599

@ChrisEdwards

Description

@ChrisEdwards

Version

Slackdump 3.1.11 built on: 2025-12-14T10:51:00Z

Description

slackdump format text panics with "slice bounds out of range [1:0]" when processing an archive that contains a thread where:

  • The thread parent message is within the archived time range
  • All thread replies are outside the archived time range

This results in getThread() returning an empty slice, and the subsequent mm[1:] panics.

Steps to Reproduce

  1. Archive a workspace with a time range that captures a thread parent but not its replies:
    slackdump archive -files=false -time-from=2026-01-19T08:00:00 -time-to=2026-01-20T07:59:59 CHANNEL_ID
  2. Run format text on the archive:
    slackdump format text ./slackdump_YYYYMMDD_HHMMSS
  3. Panic occurs if any channel has a thread where parent exists but replies don't

Stack Trace

panic: runtime error: slice bounds out of range [1:0]

goroutine 1 [running]:
github.com/rusq/slackdump/v3/cmd/slackdump/internal/format.getThread({0x10366adb8, 0x14000690930}, {0x103673410, 0x140006c83c0}, {0x14000a18210, 0x9}, {0x14000d7acc0, 0x11})
        github.com/rusq/slackdump/v3/cmd/slackdump/internal/format/source.go:131 +0x250
github.com/rusq/slackdump/v3/cmd/slackdump/internal/format.getChannel-range1(...)
        github.com/rusq/slackdump/v3/cmd/slackdump/internal/format/source.go:102 +0x284
...

Root Cause

In cmd/slackdump/internal/format/source.go, the getThread function at line 131:

func getThread(ctx context.Context, src source.Sourcer, chanID string, ts string) ([]types.Message, error) {
    itt, err := src.AllThreadMessages(ctx, chanID, ts)
    if err != nil {
        return nil, err
    }
    var mm []types.Message
    for threadMsg, err := range itt {
        if err != nil {
            return nil, err
        }
        mm = append(mm, types.Message{Message: threadMsg})
    }
    return mm[1:], nil  // <-- panics if mm is empty or has only 1 element
}

The mm[1:] slice operation assumes there's at least one message to skip (the thread parent), but when the thread replies are outside the time range, mm can be empty.

Suggested Fix

Add a bounds check before slicing:

if len(mm) <= 1 {
    return nil, nil // No thread replies to return
}
return mm[1:], nil

Workaround

Currently, the only workaround is to avoid archiving channels that have threads where the parent is in-range but replies are out-of-range, which is difficult to predict.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions