Tencent/QMUI_Android · error · IOException
Failed to get output stream.
Error message
Failed to get output stream.
What it means
After the MediaStore record is created, saveToStore calls contentResolver.openOutputStream(uri). If the provider refuses to hand out an output stream (null), an IOException("Failed to get output stream.") is thrown so the write aborts cleanly and pending cleanup runs.
Source
Thrown at photo/src/main/java/com/qmuiteam/photo/util/QMUIPhotoHelper.kt:71
put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis())
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, dirName)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var stream: OutputStream? = null
var uri: Uri? = null
try {
uri = context.contentResolver.insert(contentUri, contentValues)
if (uri == null) {
throw IOException("Failed to create new MediaStore record.")
}
stream = context.contentResolver.openOutputStream(uri)
if (stream == null) {
throw IOException("Failed to get output stream.")
}
writer.invoke(stream)
contentValues.clear()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
context.contentResolver.update(uri, contentValues, null, null)
}
return uri
} catch (e: Throwable) {
Log.i(TAG, "saveToStore failed.", e)
if (uri != null) {
context.contentResolver.delete(uri, null, null)
}
} finally {
stream?.close()
}
return null
}View on GitHub (pinned to 026e7d4866)
Solutions
- Retry the save operation; transient provider failures are common.
- Check free storage space before writing.
- Verify the returned Uri is still valid (contentResolver.getType(uri) != null) before opening the stream.
- Catch the IOException and delete the orphan pending record if needed.
Example fix
// before
stream = context.contentResolver.openOutputStream(uri) ?: throw IOException(...)
// after
try { saveToStore(...) } catch (e: IOException) { cleanupPendingUri(uri); retryLater() } Defensive patterns
Strategy: retry
Validate before calling
val stream = context.contentResolver.openOutputStream(uri)
if (stream == null) { /* schedule retry or cleanup pending record */ } Try / catch
var attempt = 0
while (attempt < 3) {
try { saveToStore(...); break } catch (e: IOException) { if (++attempt == 3) report(e) }
} Prevention
- Retry transient ContentResolver failures
- Delete orphan IS_PENDING records on failure
- Verify uri validity with contentResolver.getType(uri) before writing
When it happens
Trigger: openOutputStream(uri) returning null even though insert succeeded — provider locked the file, IS_PENDING conflict, storage suddenly unavailable, or security exception surfaced as null.
Common situations: Concurrent modification of the MediaStore entry; low storage making the file unopenable; OEM provider quirks; passing a uri that was invalidated after insert.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- Failed to create new MediaStore record.
- Can not perform LatestVisitRecord, %s must be annotated by L
- Fragment(%s) not attached to Activity.
- Can not find the fragment container provider.
- requestCode can not be %s
AI-assisted analysis of Tencent/QMUI_Android@026e7d4866 (2026-09-06).
Data as JSON: /api/errors/fa4eeb814ad4689f.
Report an issue: GitHub.