dbt-labs/dbt-core · error
role must be a string
Error message
role must be a string
What it means
This error is raised by the `grant_access_to` adapter method when the `role` argument is provided but is not a Jinja string. The method allows `role` to be None/undefined (no role grant), but if a value is passed it must be coercible to a string via `as_str()`. dbt-core throws the equivalent Python error when `grant_access_to` receives a non-string role.
Source
Thrown at crates/dbt-adapter/src/adapter/mod.rs:2312
let database = grant_target.project.as_deref().ok_or_else(|| {
minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
"project in a GrantAccessToTarget cannot be empty",
)
})?;
let schema = grant_target.dataset.as_deref().ok_or_else(|| {
minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
"dataset in a GrantAccessToTarget cannot be empty",
)
})?;
let role = if role_val.is_none() || role_val.is_undefined() {
None
} else {
Some(role_val.as_str().ok_or_else(|| {
minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
"role must be a string",
)
})?)
};
let entity = downcast_value_to_dyn_base_relation(entity_val)?;
let mut conn =
adapter.borrow_tlocal_connection(Some(state), node_id_from_state(state))?;
let result = adapter.grant_access_to(
state,
conn.as_mut(),
&entity,
entity_type,
role,
database,
schema,View on GitHub (pinned to 0267ce9170)
Solutions
- Ensure the role argument is a quoted string, e.g. grant_access_to(relation, privilege, role='reporter')
- If the role may be absent, omit the kwarg entirely or pass an actually-undefined variable instead of none
- Convert non-string values before calling: role=my_role|string
- Inspect the value with log() or print() to confirm its type before the call
Example fix
// before (Jinja)
{{ grant_access_to(relation, 'select', role=none) }}
// after
{{ grant_access_to(relation, 'select', role='reporter') }} Defensive patterns
Strategy: type-guard
Validate before calling
{% if role is defined and role is not none and role is not string %}
{{ exceptions.raise_compiler_error("role must be a string, got: " ~ role) }}
{% endif %} Type guard
{% macro is_jinja_string(v) %}
{{ return(v is string) }}
{% endmacro %} Try / catch
{% set res = adapter.dispatch('grant_access_to')(relation, privilege, role=role if role is string else none) %} Prevention
- Always pass role as a quoted string literal or a string-typed variable
- Omit the role kwarg rather than passing none when no role is needed
- Use |string filter on computed values before passing
When it happens
Trigger: Calling `grant_access_to(relation, privilege, role=...)` from a Jinja macro with a non-string role value, e.g. `role=none` that is not actually undefined (a literal none Value rather than undefined), a numeric, boolean, or dict/list value, or a Jinja object that does not implement string conversion.
Common situations: Passing a Jinja `none` literal which is neither undefined nor a string; passing an integer role ID; passing a config-derived value that resolves to a dict; typo where the caller passes a variable holding an object instead of its string name.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Invalid arguments to doc macro
- describe_dynamic_table is not supported by the {} adapter
- describe_interactive_table is not supported by the {} adapte
- invalid return value
- target is not set in state
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/3bbad8ea1fb32fb5.
Report an issue: GitHub.