Skip to content

iOS: bound stream writer threads silently swallow errors #438

@jkmassel

Description

@jkmassel

Summary

The background writer threads used for bound stream pairs silently swallow all errors. If a FileHandle.read() fails mid-stream or OutputStream.write() returns an error, the thread exits without logging or propagating the failure. The output stream closes, the input stream sees EOF, and URLSession receives fewer bytes than Content-Length promised — resulting in a network error with no indication of the root cause.

Locations

On trunk:

  • RequestBody.makePipedFileSliceStreamios/Sources/GutenbergKitHTTP/RequestBody.swift (~line 217)

On feat/leverage-host-media-processing (PR #419):

  • DefaultMediaUploader.multipartBodyStreamios/Sources/GutenbergKit/Sources/Media/MediaUploadServer.swift (same pattern, copied from above)

The pattern

Thread.detachNewThread {
    defer {
        output.close()
        try? fileHandle.close()
    }

    var remaining = length
    while remaining > 0 {
        let chunkSize = min(65_536, remaining)
        // FileHandle.read error silently swallowed by try?
        guard let chunk = try? fileHandle.read(upToCount: chunkSize),
              !chunk.isEmpty else {
            break  // silent exit — no logging
        }
        // write error — silent exit
        guard Self.writeAll(chunk, to: output) else { return }
        remaining -= chunk.count
    }
}

Problems

  1. No logging: When the writer thread fails, there is no log message indicating what went wrong (I/O error, stream closed, etc.), making production issues hard to diagnose.
  2. No error propagation: The caller has no way to distinguish "stream completed successfully" from "stream failed after 50% of the file." Both look like the output stream closing.
  3. Root cause masked: URLSession will report a generic network/content-length mismatch error, hiding the actual cause (disk I/O failure, file deleted, permissions changed, etc.).

Suggested improvements

  • Log errors from FileHandle.read() and OutputStream.write() before exiting
  • Consider using os.Logger consistent with other upload server logging
  • Optionally, track whether the writer completed successfully so callers can report a more specific error

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions