BoundaryML/baml · info

Exiting.

Error message

Exiting.

What it means

`baml deploy` may ask interactively whether to append generators to the user's config. If the user answers no, the CLI intentionally aborts with 'Exiting.' — this is a user-requested cancel, not a bug.

Solutions

  1. Answer 'Yes' at the prompt to allow the CLI to append generators to your config
  2. Manually add the generator blocks to your baml config before deploying
  3. Run non-interactively only after the config already contains the generators
Defensive patterns

Strategy: validation

Validate before calling

// check generators exist in config before deploying
const cfg = JSON.parse(fs.readFileSync('baml_config.json'));
if (!cfg.generators || cfg.generators.length === 0) addGeneratorsFirst();

Try / catch

try {
  await deploy();
} catch (e) {
  if (String(e).includes('Exiting.')) console.log('Deploy cancelled by user');
}

Prevention

When it happens

Trigger: Running deploy_new_project against a project whose generators are not yet in the config, and answering 'No' at the 'should append generators?' dialog prompt.

Common situations: First-time deploy of a project, scripted/CI environments where the interactive prompt gets a default-negative or EOF answer.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/9c9ec577732587ea. Report an issue: GitHub.

Appendix: source

Thrown at engine/cli/src/deploy.rs:284

            None => ("generators.baml".into(), String::new(), new_generator_block),
        };

        println!();
        println!("Your project will be deployed with the following configuration:");
        print_diff(&prev_generators, &new_generators);
        println!();

        let should_append = Confirm::with_theme(&ColorfulTheme::default())
            .with_prompt(format!(
                "Save configuration to {} and deploy your project?",
                path.display()
            ))
            .show_default(true)
            .interact()
            .context("Failed to wait for user interaction")?;

        if !should_append {
            anyhow::bail!("Exiting.");
        }

        let generator_abspath = std::path::Path::new(&self.from).join(&path);
        log::debug!("Will write generators to {}", generator_abspath.display());
        let mut file = std::fs::OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(false) // This is the default. Linter complains if not added.
            .open(&generator_abspath)
            .context(format!("Failed to open {}", generator_abspath.display()))?;
        writeln!(file, "{new_generators}").context(format!(
            "Failed to write to {}",
            generator_abspath.display()
        ))?;

        let project_id = match get_or_create {
            GetOrCreateProjectResult::Existing(project) => project.project_id,
            GetOrCreateProjectResult::ToBeCreated(project_fqn) => {

View on GitHub (pinned to bd85ce9dee)