BoundaryML/baml · error · minijinja::Error

Cannot parse begin date

Error message

Cannot parse begin date

What it means

The date_between Jinja filter parses the row `date`, then the `begin` bound, then the `end` bound. If `begin` cannot be parsed into a date by parse_date, the filter raises a minijinja SyntaxError 'Cannot parse begin date' instead of returning false (the row date itself failing to parse silently yields false).

Solutions

  1. Correct the `begin` argument to match the format expected by parse_date (e.g. YYYY-MM-DD)
  2. Pre-validate or normalize the begin date in the template before calling date_between
  3. Log/print the failing begin value to confirm what is actually passed
  4. If the value is dynamic, wrap the filter call so a parse error surfaces the raw input

Example fix

// before
{{ date_between(post.created_at, "01/02/2024", "31/02/2024") }}
// after
{{ date_between(post.created_at, "2024-02-01", "2024-02-29") }}
Defensive patterns

Strategy: validation

Validate before calling

const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
if (!ISO_DATE.test(begin)) throw new Error(`begin must be YYYY-MM-DD, got: ${begin}`);

Try / catch

{% if begin is string and begin|length == 10 %}
  {{ date_between(d, begin, end) }}
{% else %}
  {{ false }}
{% endif %}

Prevention

When it happens

Trigger: Calling date_between(date, begin, end) where `begin` is not in the format parse_date accepts (wrong format, empty string, or a non-date expression).

Common situations: Templates passing user-supplied or locale-formatted begin dates; hardcoded date strings using a format different from what parse_date expects (e.g. YYYY/MM/DD vs YYYY-MM-DD).

Related errors


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

Appendix: source

Thrown at engine/boundary-udf/src/lib.rs:85

    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        // Use the pointer address to hash the expression
        std::ptr::hash(self.0, state);
    }
}

// NOTE: (Jesus) Could use real date type
fn date_between(date: String, begin: String, end: String) -> Result<bool, minijinja::Error> {
    fn parse_date(date: &str) -> chrono::ParseResult<chrono::NaiveDate> {
        chrono::NaiveDate::parse_from_str(date, "%Y-%m-%d")
    }

    // NOTE: (Jesus) This will be parsing `begin` and `end` dates for all rows and `date` for all date
    // comparisons.
    let Ok(date) = parse_date(&date) else {
        return Ok(false);
    };
    let begin = parse_date(&begin).map_err(|_| {
        minijinja::Error::new(minijinja::ErrorKind::SyntaxError, "Cannot parse begin date")
    })?;
    let end = parse_date(&end).map_err(|_| {
        minijinja::Error::new(minijinja::ErrorKind::SyntaxError, "Cannot parse end date")
    })?;

    Ok(date >= begin && date <= end)
}

pub mod tests {
    //! Utilities for testing
    use crate::{config::UDFConfig, read_udf_config};

    pub fn load_sample_udf() -> UDFConfig {
        use anyhow::Context;
        read_udf_config("./sample-prices.yaml")
            .context("load sample UDF config")
            .unwrap()
    }

View on GitHub (pinned to bd85ce9dee)