{"record":{"id":"1acc2c112b8ee749","repo":"prestodb/presto","slug":"failed-to-scan-table-file-tasks","errorCode":null,"errorMessage":"Failed to scan table file tasks","messagePattern":"Failed to scan table file tasks","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"critical","filePath":"presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java","lineNumber":1894,"sourceCode":"        }\n\n        int minInputFiles = parseMinInputFiles(options);\n        if (minInputFiles <= 1) {\n            return tasks;\n        }\n\n        // Group files by partition\n        Map<String, List<FileScanTask>> partitionGroups = new HashMap<>();\n        Map<String, Set<String>> partitionFilePathGroups = new HashMap<>();\n        try (CloseableIterable<FileScanTask> autoCloseTasks = tasks) {\n            for (FileScanTask task : autoCloseTasks) {\n                String partitionKey = getPartitionKey(task);\n                partitionGroups.computeIfAbsent(partitionKey, k -> new ArrayList<>()).add(task);\n                partitionFilePathGroups.computeIfAbsent(partitionKey, k -> new HashSet<>()).add(task.file().location());\n            }\n        }\n        catch (IOException e) {\n            throw new UncheckedIOException(\"Failed to scan table file tasks\", e);\n        }\n\n        // Collect tasks from partitions that meet the threshold\n        List<FileScanTask> filteredTasks = new ArrayList<>();\n        for (String partitionKey : partitionFilePathGroups.keySet()) {\n            if (partitionFilePathGroups.get(partitionKey).size() >= minInputFiles) {\n                filteredTasks.addAll(partitionGroups.get(partitionKey));\n            }\n        }\n        return CloseableIterable.withNoopClose(filteredTasks);\n    }\n\n    /**\n     * Filters files by individual file criteria using OR logic.\n     * Selects files that are too small (< min-file-size-bytes) OR too large (> max-file-size-bytes).\n     * If rewrite-all is true, skips filtering and returns all tasks.\n     *\n     * @param tasks all available tasks","sourceCodeStart":1876,"sourceCodeEnd":1912,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java#L1876-L1912","documentation":"IcebergUtil scans a table's FileScanTasks (via Iceberg's TableScan tasks) to group files by partition for the optimize/rewrite planner. Reading the tasks performs I/O over manifest/data file metadata; if that I/O throws IOException, it is wrapped in UncheckedIOException with the message 'Failed to scan table file tasks' so it can propagate from the stream/loop.","triggerScenarios":"Invoking table scan tasks during optimize when underlying storage is unavailable or unreadable: missing/deleted manifest or data files listed in metadata, HDFS/S3 connectivity failures, permission errors, or corrupt manifest avro files.","commonSituations":"Objects deleted from object storage out-of-band (retention job removing files still referenced by manifests); expired credentials to S3/GCS; HDFS NameNode unreachable; network partition mid-scan; manually cleaned-up table locations.","solutions":["Check storage connectivity/credentials (S3/HDFS/GCS access) and retry the operation once the backend is reachable.","Verify that all files referenced by the table's manifests exist — restore accidentally deleted files or run metadata repair.","Inspect the wrapped cause (getCause()) from the UncheckedIOException for the precise storage error (403, FileNotFoundException, timeout).","If files are orphaned/dangling in manifests, expire snapshots or use Iceberg remove-orphan-files/repair tooling to realign metadata with storage."],"exampleFix":"// before\ntry { scanTasks = table.newScan().planTasks(); ... }\ncatch (UncheckedIOException e) { LOG.error(\"scan failed\", e); } // cause hidden\n// after\ntry { scanTasks = table.newScan().planTasks(); ... }\ncatch (UncheckedIOException e) {\n  LOG.error(\"Failed to scan table file tasks: {}\", e.getCause().getMessage(), e.getCause());\n  throw e; // or retry against recovered storage\n}","handlingStrategy":"try-catch","validationCode":"// preflight: confirm table location and a sample file are reachable before scanning\nboolean reachable = fs.exists(new Path(tableLocation, \"metadata\"));","typeGuard":null,"tryCatchPattern":"try {\n    scanTableFileTasks(table);\n} catch (UncheckedIOException e) {\n    IOException cause = e.getCause();\n    if (cause instanceof FileNotFoundException) {\n        // missing manifest/data file: repair metadata or restore object\n    } else {\n        // storage connectivity/permission issue: retry with backoff\n    }\n    throw e;\n}","preventionTips":["Never delete objects from table storage out-of-band; always expire snapshots through Iceberg APIs.","Keep storage credentials fresh and scoped for the connector's runtime user.","Monitor storage backend health before running optimize/rewrite maintenance jobs.","Always unwrap and log getCause() of UncheckedIOException for root-cause triage."],"tags":["iceberg","io","storage","file-scan"],"backgroundTag":"storage-io-failure","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}