Hmbown/CodeWhale · error · anyhow

Source is disabled or its workspace is untrusted

Error message

Source is disabled or its workspace is untrusted

What it means

On approval, codewhale re-checks `source_blocked(context, &candidate)` just before committing. If the source is disabled or its workspace is not trusted at apply time, the import is refused — the preview-time trust state is re-verified to avoid importing from a source that became untrusted.

Solutions

  1. Trust the workspace the source lives in (respond to the trust prompt or add it to trusted workspaces), then re-apply.
  2. Re-enable the disabled source if it should be imported.
  3. Re-run `/mcp import` to regenerate a preview that reflects the current trust/disabled state.

Example fix

// before (untrusted workspace)
codewhale mcp import approve <token>
// after
codewhale workspace trust /path/to/project
codewhale mcp import approve <token>
Defensive patterns

Strategy: validation

Validate before calling

let (candidates, _) = context.discover();
if let Some(c) = candidates.iter().find(|c| candidate_id(c) == id) {
    if source_blocked(&context, c) {
        eprintln!("source is blocked: enable it or trust the workspace first");
    }
}

Try / catch

match apply_reviewed_import(...) {
    Err(e) if e.to_string().contains("disabled or its workspace is untrusted") => {
        // trust the workspace / re-enable source, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Approving an import where, at apply time, the candidate's source is marked disabled in the merged view, or the workspace containing the source file is not in the trusted-workspace set (e.g. trust was revoked or the file moved to an untrusted directory).

Common situations: User declined a workspace-trust prompt earlier; the source config lives in a new project directory that has not been marked trusted; an admin policy disabled the source after the preview.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/17a5647d825c78ab. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/mcp/external_import.rs:684

) -> anyhow::Result<ImportReceipt> {
    anyhow::ensure!(
        matches!(decision, ImportDecision::Approve | ImportDecision::Decline),
        "Choose approve or decline"
    );
    let (candidate, revision) = super::mutate_config(context.mcp_path, Some(revision), |config| {
        let (candidates, _) = context.discover();
        let candidate = candidates
            .into_iter()
            .find(|candidate| candidate_id(candidate) == id)
            .ok_or_else(|| {
                anyhow::anyhow!("Reviewed source is unavailable; refresh the import preview")
            })?;
        anyhow::ensure!(
            candidate.content_hash == hash,
            "Source changed; refresh the import preview"
        );
        if decision == ImportDecision::Approve {
            anyhow::ensure!(
                !source_blocked(context, &candidate),
                "Source is disabled or its workspace is untrusted"
            );
            anyhow::ensure!(
                !context.merged()?.servers.contains_key(&candidate.name)
                    && !config.servers.contains_key(&candidate.name),
                "A managed, project or plugin connector already uses this name"
            );
            let mut server = candidate.server.clone();
            server.enabled = false;
            server.disabled = true;
            config.servers.insert(candidate.name.clone(), server);
        }
        Ok(candidate)
    })?;
    let decisions = HashMap::from([(candidate.name.clone(), decision)]);
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)

View on GitHub (pinned to 73e0f67d83)