{"record":{"id":"282ef709bd4d625b","repo":"lingochamp/FileDownloader","slug":"getlargesofarbytes","errorCode":null,"errorMessage":"getLargeSofarBytes","messagePattern":"getLargeSofarBytes","errorType":"exception","errorClass":"NoFieldException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/liulishuo/filedownloader/message/MessageSnapshot.java","lineNumber":63,"sourceCode":"\n    @Override\n    public int getRetryingTimes() {\n        throw new NoFieldException(\"getRetryingTimes\", this);\n    }\n\n    @Override\n    public boolean isResuming() {\n        throw new NoFieldException(\"isResuming\", this);\n    }\n\n    @Override\n    public String getEtag() {\n        throw new NoFieldException(\"getEtag\", this);\n    }\n\n    @Override\n    public long getLargeSofarBytes() {\n        throw new NoFieldException(\"getLargeSofarBytes\", this);\n    }\n\n    @Override\n    public long getLargeTotalBytes() {\n        throw new NoFieldException(\"getLargeTotalBytes\", this);\n    }\n\n    @Override\n    public int getSmallSofarBytes() {\n        throw new NoFieldException(\"getSmallSofarBytes\", this);\n    }\n\n    @Override\n    public int getSmallTotalBytes() {\n        throw new NoFieldException(\"getSmallTotalBytes\", this);\n    }\n\n    @Override","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/lingochamp/FileDownloader/blob/6237a8cac174bcc916e4342b14ab1ab72a5768d4/library/src/main/java/com/liulishuo/filedownloader/message/MessageSnapshot.java#L45-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check snapshot.getStatus() before reading progress fields; only call getLargeSofarBytes() on progress/connected (large-file) snapshots.","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.","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.","Ensure the correct snapshot subclass is created via MessageSnapshot.CREATOR for the status rather than constructing a base/subclass that lacks the field."],"exampleFix":"// before\n@Override public void progress(FileDownloadTask task, int sofar, int total) {\n    long sofarBytes = task.getMessageSnapshot().getLargeSofarBytes();\n}\n\n// after\n@Override public void progress(FileDownloadTask task, int sofar, int total) {\n    MessageSnapshot snap = task.getMessageSnapshot();\n    long sofarBytes = snap.isLargeFile()\n        ? snap.getLargeSofarBytes()\n        : snap.getSmallSofarBytes();\n}","handlingStrategy":"type-guard","validationCode":"// Safe only for large-file snapshots with byte fields\npublic static boolean hasLargeProgress(IMessageSnapshot s) {\n    return s.isLargeFile()\n        && (s.getStatus() == FileDownloadStatus.progress\n            || s.getStatus() == FileDownloadStatus.connected);\n}","typeGuard":"public static boolean canReadLargeSofar(IMessageSnapshot s) {\n    return s.isLargeFile()\n        && (s.getStatus() == FileDownloadStatus.progress\n            || s.getStatus() == FileDownloadStatus.connected);\n}\n// usage: if (canReadLargeSofar(snap)) long sofar = snap.getLargeSofarBytes();","tryCatchPattern":"long sofar;\ntry {\n    sofar = snapshot.getLargeSofarBytes();\n} catch (IllegalStateException e) {\n    // NoFieldException: field absent for this status\n    sofar = lastKnownSofar; // fallback to cached progress\n}","preventionTips":["Always switch on getStatus() before reading any IMessageSnapshot accessor.","Use isLargeFile() to pick the small vs large accessor pair.","Never cache snapshots across status changes and query them later; copy out the values you need when the callback fires.","Cover each listener callback with tests that exercise every download status."],"tags":["android","filedownloader","message-snapshot","illegal-state"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6237a8cac174bcc916e4342b14ab1ab72a5768d4","analyzedAt":"2026-09-08T23:50:48.168Z","contentChangedAt":"2026-09-08T23:50:48.168Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}