flxzt/rnote · error · anyhow::Error
Could not get a path for file
Error message
Could not get a path for file: `{file:?}`. What it means
save_document_to_file writes the document to a user-chosen Gio::File. The writer needs a real filesystem path (and basename) to serialize to; when the chosen File has no path (non-native location such as a portal handle or unusual URI), path() is None, save-in-progress is reset, and this error is thrown.
Solutions
- Choose a native local directory in the save dialog (local filesystem path), then move/copy the saved file to remote targets afterwards.
- In the caller, check file.path().is_some() before invoking save_document_to_file and fall back to load_bytes + temp-file write + copy for pathless files.
- Use file.load_bytes()/create-on-temp then gio copy into the destination File instead of requiring a direct path.
Example fix
// before
let filepath = file.path().ok_or_else(|| {
self.set_save_in_progress(false);
anyhow::anyhow!("Could not get a path for file: `{file:?}`.")
})?;
// after
let Some(filepath) = file.path() else {
self.set_save_in_progress(false);
anyhow::bail!(
"Cannot save to non-native location {file:?}; pick a local folder."
);
}; Defensive patterns
Strategy: validation
Validate before calling
// rust
if file.path().is_none() {
eprintln!("target {:?} has no native path; choose a local folder or copy the result", file.uri());
} Type guard
fn is_native_target(f: &gio::File) -> bool { f.path().is_some() } Try / catch
match canvas.save_document_to_file(&file, ...).await {
Ok(()) => {},
Err(e) if e.to_string().contains("Could not get a path") => {
// save to temp file, then gio copy into `file`
}
Err(e) => return Err(e),
} Prevention
- Configure the save dialog to local folders, or handle remote targets via copy-from-temp
- Always reset save_in_progress on early error returns (the code does; keep that pattern)
- For flatpak, be aware portal-picked files may be pathless — test save flows in sandbox
- If you must support remote targets, implement bytes -> temp file -> gio File::copy
When it happens
Trigger: dialog_save_doc_as -> save_document_to_file with a File chosen from a non-native source (gvfs/network location, document portal fd, URI without file:// scheme) where file.path() returns None.
Common situations: Saving via flatpak document portal into odd locations; picking an MTP/phone or network share target in the save dialog whose Gio::File has no native path; passing a constructed URI instead of a local path to the save API.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Could not open file ' ', file path is None.
- Can't create-replace file that has no path.
- Could not retrieve basename for file
- Supplied target file
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/5ac28ee2199f195a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-ui/src/canvas/imexport.rs:229
/// Saves the document to the given file.
///
/// Returns:
/// - `Ok(true)` if saving was successful
/// - `Ok(false)` if a save was already in progress (and thus this function didn't do anything)
/// - `Err(e)` when saving failed in any way
#[tracing::instrument(skip_all, fields(path = format!("{:?}", file.path())))]
pub(crate) async fn save_document_to_file(&self, file: &gio::File) -> anyhow::Result<bool> {
// skip saving when it is already in progress
if self.save_in_progress() {
debug!("Returning early, saving file is already in progress");
return Ok(false);
}
self.set_save_in_progress(true);
debug!("Saving file is now in progress");
let filepath = file.path().ok_or_else(|| {
self.set_save_in_progress(false);
anyhow::anyhow!("Could not get a path for file: `{file:?}`.")
})?;
let basename = file.basename().ok_or_else(|| {
self.set_save_in_progress(false);
anyhow::anyhow!("Could not retrieve basename for file: `{file:?}`.")
})?;
let rnote_bytes_receiver = self
.engine_ref()
.save_as_rnote_bytes(basename.to_string_lossy().to_string());
let mut skip_set_output_file = false;
if let Some(output_filepath) = self.output_file().and_then(|f| f.path())
&& crate::utils::paths_abs_eq(output_filepath, &filepath).unwrap_or(false)
{
skip_set_output_file = true;
}
self.dismiss_output_file_modified_toast();
View on GitHub (pinned to bbc5354502)