MuntashirAkon/AppManager · error · IOException

Scan error:

Error message

Scan error: 

What it means

VirusTotal file-report/scan request completed but the API returned an error payload instead of a scan report. fetchFileReportOrScan unwraps ResponseV3 and, when there is no response object but an error string, throws IOException("Scan error: " + error) to surface the remote failure to the caller.

Solutions

  1. Inspect responseReport.error in the message to identify the remote cause (rate limit vs auth vs not-found).
  2. Verify the VirusTotal API key is valid and has remaining quota.
  3. Respect the waitDuration (30s) and retry with backoff when the error indicates rate limiting or pending analysis.
  4. Catch the IOException at the call site and surface a user-visible failure instead of crashing.

Example fix

// before
throw new IOException("Scan error: " + responseReport.error);
// after
if (responseReport.error != null && responseReport.error.contains("rate limit")) {
    throw new IOException("VirusTotal rate limit exceeded, try again later");
}
throw new IOException("Scan error: " + responseReport.error);
Defensive patterns

Strategy: try-catch

Validate before calling

if (apiKey == null || apiKey.isEmpty()) throw new IllegalStateException("VT API key missing");
if (responseReport.error != null && !responseReport.error.isEmpty()) {
    // error already known before unwrapping: handle manually
}

Try / catch

try {
    virusTotal.fetchFileReportOrScan(file, waitDuration, response);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().contains("rate limit")) {
        // back off and retry later
    } else {
        // show scan-unavailable state to user
    }
}

Prevention

When it happens

Trigger: Calling fetchFileReportOrScan when the VirusTotal v3 API responds with an error: rate limit exceeded, invalid/expired API key, file not yet analyzed and no scan queued, or a network/HTTP failure captured into responseReport.error.

Common situations: Free-tier API quota exhausted (HTTP 429), wrong VT API key, polling too early before the waitDuration elapses, transient VirusTotal outages.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/a55e5195943b4b1b. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VirusTotal.java:170

        int waitDuration = 60_000;
        while (queued || responseReport.shouldRetry()) {
            if (waitFirst) {
                // Effectively makes it a do-while loop
                waitFirst = false;
            } else {
                responseReport = fetchFileReport(checksum);
                queued = responseReport.response != null && !responseReport.response.hasReport();
            }
            // Wait for result: First wait for 1 minute, then for 30 seconds
            // We won't do it less than 30 seconds since the API has a limit of 4 request/minute
            SystemClock.sleep(waitDuration);
            // TODO: 23/5/22 Wait duration should be according to the fileSize
            waitDuration = 30_000;
        }
        if (responseReport.response != null) {
            response.onReportReceived(responseReport.response);
        } else {
            throw new IOException("Scan error: " + responseReport.error);
        }
    }

    @WorkerThread
    @NonNull
    public ResponseV3<String> uploadFile(@NonNull String filename, @NonNull InputStream is)
            throws IOException {
        return uploadFile(filename, is, null);
    }

    @WorkerThread
    @NonNull
    public ResponseV3<String> uploadFile(@NonNull String filename, @NonNull InputStream is,
                                         @Nullable String password) throws IOException {
        URL url = new URL(URL_FILE_UPLOAD);
        return uploadAnyFile(url, filename, is, password);
    }

View on GitHub (pinned to 0152f468fc)