clash-verge-rev/clash-verge-rev · error · anyhow::Error
file field is required when file_data is provided
Error message
file field is required when file_data is provided
What it means
Thrown by IProfiles::append_item when a PrfItem carries `file_data` (inline content to be written to disk) but the `file` field (the destination filename) is None. The preceding `bail!` covers the same case with a different message; this `ok_or_else` is the fall-through guard after the `bail!` branch is logically unreachable. Together they enforce the invariant that inline file data must name a target file.
Source
Thrown at src-tauri/src/config/profiles.rs:222
/// if the file_data is some
/// then should save the data to file
pub async fn append_item(&mut self, item: &mut PrfItem) -> Result<()> {
let uid = &item.uid;
if uid.is_none() {
bail!("the uid should not be null");
}
// save the file data
// move the field value after save
if let Some(file_data) = item.file_data.take() {
if item.file.is_none() {
bail!("the file should not be null");
}
let file = item
.file
.clone()
.ok_or_else(|| anyhow::anyhow!("file field is required when file_data is provided"))?;
let path = dirs::app_profiles_dir()?.join(file.as_str());
fs::write(&path, file_data.as_bytes())
.await
.with_context(|| format!("failed to write to file \"{file}\""))?;
}
if self.current.is_none() && (item.itype == Some("remote".into()) || item.itype == Some("local".into())) {
self.current = uid.to_owned();
}
if self.items.is_none() {
self.items = Some(vec![]);
}
if let Some(items) = self.items.as_mut() {
items.push(item.to_owned());
}View on GitHub (pinned to 5cad0f2799)
Solutions
- Set `item.file` to a valid filename (e.g. the uid + `.yaml`) whenever `item.file_data` is `Some`.
- Validate the payload on the Tauri command boundary before calling append_item, rejecting items where file_data is present but file is absent.
- If importing programmatically, derive the filename from the uid when it is missing.
Example fix
// before
item.file_data = Some(yaml.to_string());
// item.file left as None
// after
item.file = Some(format!("{}.yaml", uid));
item.file_data = Some(yaml.to_string()); Defensive patterns
Strategy: validation
Validate before calling
fn validate_item(item: &PrfItem) -> Result<(), String> {
if item.file_data.is_some() && item.file.is_none() {
return Err("file field is required when file_data is provided".into());
}
Ok(())
} Type guard
fn item_is_well_formed(item: &PrfItem) -> bool {
!(item.file_data.is_some() && item.file.is_none())
} Try / catch
if let Err(e) = profiles.append_item(&mut item).await {
if e.to_string().contains("file field is required") {
// surface to UI: ask user for filename or derive from uid
}
} Prevention
- On the Tauri command boundary, reject payloads where file_data is set but file is absent.
- Derive item.file from item.uid at construction time when importing local content.
- Add a unit test that asserts append_item errors on file_data-without-file.
When it happens
Trigger: Constructing a PrfItem programmatically and setting `file_data` without setting `file`; deserializing a profile item from JSON/Tauri command payload that includes file_data but omits or nulls the file field.
Common situations: Frontend sends a 'create local profile' payload with the raw YAML content but forgets to send the filename; a migration script copies file_data between items but drops the file field; a test fixture builds a PrfItem incompletely.
Related errors
- failed to parse subscription URL: {:?}, input: {}
- listener address must include a port
- {key} must be an integer between 1 and 65535
- {outcome}
- Invalid vless uri
AI-assisted analysis of clash-verge-rev/clash-verge-rev@5cad0f2799 (2026-08-12).
Data as JSON: /api/errors/d8206d8ef86ea856.
Report an issue: GitHub.