lingochamp/FileDownloader · error · NoFieldException

getLargeSofarBytes

Error message

getLargeSofarBytes

What it means

MessageSnapshot's abstract base class implements getLargeSofarBytes() to throw NoFieldException (an IllegalStateException). Only concrete snapshot subclasses that actually carry a 'sofar bytes' field (e.g. LargeMessageSnapshot.ProgressMessageSnapshot, ConnectedMessageSnapshot) override it with a real value. The exception means the accessor was called on a snapshot whose download status has no such field (e.g. a StartedMessageSnapshot or a WarnMessageSnapshot), signaling a logic bug in whoever consumed the snapshot.

Solutions

  1. Check snapshot.getStatus() before reading progress fields; only call getLargeSofarBytes() on progress/connected (large-file) snapshots.
  2. Fix the internal caller (update or message-conversion code) to pick fields appropriate to the snapshot's concrete class instead of unconditionally querying all accessors.
  3. If you need byte counts regardless of status, store the last valid progress values from the progress callback and use those when the status is not progress.
  4. Ensure the correct snapshot subclass is created via MessageSnapshot.CREATOR for the status rather than constructing a base/subclass that lacks the field.

Example fix

// before
@Override public void progress(FileDownloadTask task, int sofar, int total) {
    long sofarBytes = task.getMessageSnapshot().getLargeSofarBytes();
}

// after
@Override public void progress(FileDownloadTask task, int sofar, int total) {
    MessageSnapshot snap = task.getMessageSnapshot();
    long sofarBytes = snap.isLargeFile()
        ? snap.getLargeSofarBytes()
        : snap.getSmallSofarBytes();
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Safe only for large-file snapshots with byte fields
public static boolean hasLargeProgress(IMessageSnapshot s) {
    return s.isLargeFile()
        && (s.getStatus() == FileDownloadStatus.progress
            || s.getStatus() == FileDownloadStatus.connected);
}

Type guard

public static boolean canReadLargeSofar(IMessageSnapshot s) {
    return s.isLargeFile()
        && (s.getStatus() == FileDownloadStatus.progress
            || s.getStatus() == FileDownloadStatus.connected);
}
// usage: if (canReadLargeSofar(snap)) long sofar = snap.getLargeSofarBytes();

Try / catch

long sofar;
try {
    sofar = snapshot.getLargeSofarBytes();
} catch (IllegalStateException e) {
    // NoFieldException: field absent for this status
    sofar = lastKnownSofar; // fallback to cached progress
}

Prevention

When it happens

Trigger: Calling IMessageSnapshot.getLargeSofarBytes() (directly or via a FileDownloadListener block) on a MessageSnapshot for a status that does not store progress bytes, such as FileDownloadStatus.started, warn, pending (small), completed, or error snapshots.

Common situations: A FileDownloadListener callback reads sofar/total bytes without checking getStatus() first; code that caches a MessageSnapshot across status changes and later reads progress fields from it; custom message routing code (like the internal update()/handoverMessage paths) forwarding snapshots of the wrong status; upgrades where a previously overridden method became a throwing base-class default.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of lingochamp/FileDownloader@6237a8cac1 (2026-09-08). Data as JSON: /api/errors/282ef709bd4d625b. Report an issue: GitHub.

Appendix: source

Thrown at library/src/main/java/com/liulishuo/filedownloader/message/MessageSnapshot.java:63

    @Override
    public int getRetryingTimes() {
        throw new NoFieldException("getRetryingTimes", this);
    }

    @Override
    public boolean isResuming() {
        throw new NoFieldException("isResuming", this);
    }

    @Override
    public String getEtag() {
        throw new NoFieldException("getEtag", this);
    }

    @Override
    public long getLargeSofarBytes() {
        throw new NoFieldException("getLargeSofarBytes", this);
    }

    @Override
    public long getLargeTotalBytes() {
        throw new NoFieldException("getLargeTotalBytes", this);
    }

    @Override
    public int getSmallSofarBytes() {
        throw new NoFieldException("getSmallSofarBytes", this);
    }

    @Override
    public int getSmallTotalBytes() {
        throw new NoFieldException("getSmallTotalBytes", this);
    }

    @Override

View on GitHub (pinned to 6237a8cac1)