GraphiteEditor/Graphite · warning

just checked there's one entry

Error message

just checked there's one entry

What it means

In the crash-recovery flow, files is a collected Vec and the code branches on files.len() == 1, then immediately does files.into_iter().next().expect("just checked there's one entry"). This expect is an invariant annotation for the compiler: the length was just checked, so next() must yield Some. It is unreachable unless the two collections diverge (e.g., a future refactor checks one Vec but iterates another).

Source

Thrown at editor/src/messages/portfolio/portfolio_message_handler.rs:500

						let base = format!("{stem}.{FILE_EXTENSION}");
						let unique = match used_names.get(&base).copied() {
							None => {
								used_names.insert(base.clone(), 1);
								base
							}
							Some(n) => {
								used_names.insert(base.clone(), n + 1);
								format!("{stem} ({n}).{FILE_EXTENSION}")
							}
						};
						(unique, content.as_bytes().to_vec())
					})
					.collect();

				const FOLDER_NAME: &str = "Graphite Recovered Documents";

				if files.len() == 1 {
					let (filename, content) = files.into_iter().next().expect("just checked there's one entry");
					responses.add(FrontendMessage::TriggerSaveFile {
						name: filename,
						folder: None,
						content: serde_bytes::ByteBuf::from(content),
					});
				} else {
					match build_recovery_zip(&files) {
						Ok(zip_bytes) => responses.add(FrontendMessage::TriggerSaveFile {
							name: format!("{FOLDER_NAME}.zip"),
							folder: None,
							content: serde_bytes::ByteBuf::from(zip_bytes),
						}),
						Err(e) => {
							log::error!("Failed to build recovery zip: {e}");
							responses.add(DialogMessage::DisplayDialogError {
								title: "Failed to download".to_string(),
								description: format!("Could not bundle the failed documents for download.\n\n{e}"),
							});

View on GitHub (pinned to c507b35645)

Solutions

  1. Prefer if let Some((filename, content)) = files.into_iter().next() which makes the branch and the extraction one atomic pattern
  2. Keep the length check and the drain adjacent so refactors cannot separate them
  3. If kept as-is, treat any hit of this expect as a logic-bug signal, not an environment problem

Example fix

// before
if files.len() == 1 {
	let (filename, content) = files.into_iter().next().expect("just checked there's one entry");
	// ...
}

// after
if let Some((filename, content)) = files.into_iter().next_if(|_| files.len() == 1) {
	// ...
}
Defensive patterns

Strategy: validation

Validate before calling

if files.len() == 1 {
	debug_assert_eq!(files.len(), 1);
	if let Some((filename, content)) = files.into_iter().next() { /* handle single file */ }
}

Prevention

When it happens

Trigger: Practically unreachable as written; would fire only if the len()==1 check and the iterated collection become different collections after refactoring, or concurrency were introduced between check and use (there is none here).

Common situations: Refactors that split or rebuild the files Vec between the length check and iteration; copy-paste of this pattern into async code where the invariant no longer holds.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/bddf3e01114a604a. Report an issue: GitHub.