nostra13/Android-Universal-Image-Loader · error · IllegalStateException
Newly created entry didn't create value for index
Error message
Newly created entry didn't create value for index {i} What it means
IllegalStateException from DiskLruCache.completeEdit: when an edit succeeds on an entry that has never been committed (not yet readable), every one of the valueCount files must have been written. If editor.written[i] is false for any index, the edit is aborted and this is thrown — the caller committed an editor without writing all values. In this library valueCount is always 1, so it means the single value file was never written before commit().
Solutions
- Only call editor.commit() after the value(s) were actually written; call editor.abort() on any failure path.
- Structure saves as: edit -> write ALL value files -> commit; wrap in try/finally that aborts on exception.
- If you use LruDiskCache.save() directly, ensure the incoming InputStream is fully copied before it returns success.
Example fix
// before
Editor editor = cache.edit(key);
// download failed, but commit anyway
editor.commit(); // IllegalStateException on new entry
// after
Editor editor = cache.edit(key);
if (editor == null) return false;
try {
boolean ok = copyStream inputStream -> editor.newOutputStream(0); // writes index 0
if (!ok) { editor.abort(); return false; }
editor.commit();
} catch (IOException e) {
editor.abort();
throw e;
} Defensive patterns
Strategy: validation
Validate before calling
Editor editor = cache.edit(key);
if (editor == null) return false; // entry being edited elsewhere
boolean allWritten = false;
try {
OutputStream os = editor.newOutputStream(0);
allWritten = copyStream(source, os, buffer); // writes every value index (here: just 0)
} finally {
if (allWritten) editor.commit(); else editor.abort();
} Try / catch
try {
writeAllValues(editor);
editor.commit();
} catch (Exception e) {
editor.abort(); // leave entry consistent instead of throwing IllegalState later
throw e;
} Prevention
- Rule: commit() only after every value file was written; abort() on every failure path.
- Use try/finally so abort() runs even when the stream copy throws.
- valueCount is 1 in this library — but keep the discipline generic: write index 0 always.
When it happens
Trigger: Calling editor.commit() (or DiskLruCache.edit succeeding internally) without ever obtaining/creating the value file: e.g. getting an Editor via cache.edit(key), skipping newOutputStream(0)/file(0) writes entirely (for instance the download failed and you still commit), then committing success=true on a brand-new entry.
Common situations: Custom code on top of DiskLruCache that commits 'successfully' on an empty/failed download path; races where the value write was skipped because a stream could not be opened; misunderstandings that commit() on an unwritten new entry is a no-op.
Related errors
- cache is closed
- cacheDir argument must be not null
- cacheMaxFileCount argument must be positive number
- cacheMaxSize argument must be positive number
- failed to delete
AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14).
Data as JSON: /api/errors/ad42e023a9b20a0e.
Report an issue: GitHub.
Appendix: source
Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/DiskLruCache.java:545
* this cache. This may be greater than the max file count if a background
* deletion is pending.
*/
public synchronized long fileCount() {
return fileCount;
}
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
Entry entry = editor.entry;
if (entry.currentEditor != editor) {
throw new IllegalStateException();
}
// If this edit is creating the entry for the first time, every index must have a value.
if (success && !entry.readable) {
for (int i = 0; i < valueCount; i++) {
if (!editor.written[i]) {
editor.abort();
throw new IllegalStateException("Newly created entry didn't create value for index " + i);
}
if (!entry.getDirtyFile(i).exists()) {
editor.abort();
return;
}
}
}
for (int i = 0; i < valueCount; i++) {
File dirty = entry.getDirtyFile(i);
if (success) {
if (dirty.exists()) {
File clean = entry.getCleanFile(i);
dirty.renameTo(clean);
long oldLength = entry.lengths[i];
long newLength = clean.length();
entry.lengths[i] = newLength;
size = size - oldLength + newLength;View on GitHub (pinned to ba33ec64d0)