{"record":{"id":"1ba76512fec7a8ae","repo":"lingochamp/FileDownloader","slug":"getsmallsofarbytes","errorCode":null,"errorMessage":"getSmallSofarBytes","messagePattern":"getSmallSofarBytes","errorType":"exception","errorClass":"NoFieldException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/liulishuo/filedownloader/message/MessageSnapshot.java","lineNumber":73,"sourceCode":"\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\n    public boolean isReusedDownloadedFile() {\n        throw new NoFieldException(\"isReusedDownloadedFile\", this);\n    }\n\n    @Override\n    public String getFileName() {\n        throw new NoFieldException(\"getFileName\", this);\n    }\n\n    @Override","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/lingochamp/FileDownloader/blob/6237a8cac174bcc916e4342b14ab1ab72a5768d4/library/src/main/java/com/liulishuo/filedownloader/message/MessageSnapshot.java#L55-L91","documentation":"getSmallSofarBytes() is another base-class accessor in MessageSnapshot that throws NoFieldException unless overridden by a snapshot carrying small-file progress (e.g. SmallMessageSnapshot.ProgressMessageSnapshot). The throw indicates the sofar-bytes field does not exist for this snapshot's status, so the query is a programming error by the consumer.","triggerScenarios":"Calling getSmallSofarBytes() on a large-file snapshot (which exposes getLargeSofarBytes instead) or on status snapshots without progress data (started, warn, completed, error, pending-large); internally reached from handoverMessage() when a status-change snapshot is inspected for progress fields.","commonSituations":"Code that reads small-file fields without checking isLargeFile(); shared listener code written for small downloads then applied to large downloads (maxBytesOverMobile / file-size thresholds); snapshots moved across process boundaries and re-inspected for fields they never carried.","solutions":["Dispatch on snapshot.isLargeFile(): use getSmallSofarBytes() only for small-file snapshots, getLargeSofarBytes() for large ones.","Check getStatus() is progress/connected before reading any sofar-bytes accessor.","Fix the internal handoverMessage() logic to only query fields present on the concrete snapshot class.","Fall back to getSmallSofarBytes()/getLargeSofarBytes() inside a try-catch for IllegalStateException if snapshot provenance cannot be determined."],"exampleFix":"// before\nint sofar = snapshot.getSmallSofarBytes();\n\n// after\nint sofar = snapshot.isLargeFile()\n    ? (int) snapshot.getLargeSofarBytes()\n    : snapshot.getSmallSofarBytes();","handlingStrategy":"type-guard","validationCode":"public static boolean hasSmallProgress(IMessageSnapshot s) {\n    return !s.isLargeFile()\n        && (s.getStatus() == FileDownloadStatus.progress\n            || s.getStatus() == FileDownloadStatus.connected);\n}","typeGuard":"public static boolean canReadSmallSofar(IMessageSnapshot s) {\n    return !s.isLargeFile()\n        && (s.getStatus() == FileDownloadStatus.progress\n            || s.getStatus() == FileDownloadStatus.connected);\n}\n// usage: int sofar = canReadSmallSofar(snap) ? snap.getSmallSofarBytes() : 0;","tryCatchPattern":"int sofar;\ntry {\n    sofar = snapshot.getSmallSofarBytes();\n} catch (IllegalStateException e) {\n    sofar = snapshot.isLargeFile()\n        ? (int) lastKnownLargeSofar\n        : lastKnownSmallSofar;\n}","preventionTips":["Check isLargeFile() before choosing small vs large accessors.","Only read progress bytes in progress/connected callbacks.","Avoid writing listener code that assumes every status provides byte counts.","Add unit tests per status so a throwing accessor is caught in CI, not production."],"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"}