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

  1. Set `item.file` to a valid filename (e.g. the uid + `.yaml`) whenever `item.file_data` is `Some`.
  2. Validate the payload on the Tauri command boundary before calling append_item, rejecting items where file_data is present but file is absent.
  3. 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

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


AI-assisted analysis of clash-verge-rev/clash-verge-rev@5cad0f2799 (2026-08-12). Data as JSON: /api/errors/d8206d8ef86ea856. Report an issue: GitHub.