Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Unit test raising error '<macro name>' is undefined. This can happen when calling a macro that does not exist. #10157

Open
2 tasks done
dbeatty10 opened this issue May 16, 2024 · 8 comments
Labels
bug Something isn't working Medium Severity bug with minor impact that does not have resolution timeframe requirement unit tests Issues related to built-in dbt unit testing functionality

Comments

@dbeatty10
Copy link
Contributor

dbeatty10 commented May 16, 2024

Is this a new bug in dbt-core?

  • I believe this is a new bug in dbt-core
  • I have searched the existing issues, and I could not find an existing issue for this bug

Current Behavior

Sometimes (but not always!), I get this compilation error when a model contains a macro:

13:04:08    Compilation Error in unit_test test__model_f (models/unit_test.yml)
  'british_colours' is undefined. This can happen when calling a macro that does not exist. Check for typos and/or install package dependencies with "dbt deps".

Expected Behavior

This seems like it should work without needing to add an override for any macros.

Steps To Reproduce

macros/my_macros.sql

{% macro british_colours() -%}
    {{ return(["grey"]) }}
{%- endmacro %}


{% macro american_colors() -%}
    {{ return(["gray"]) }}
{%- endmacro %}

models/_unit_tests.yml

unit_tests:
  - name: test__model_f
    model: model_f
    given: []
    expect:
      rows:
        - {id: 1}

models/model_f.sql

{% set a_values = british_colours() %}
{% set b_values = american_colors() %}

select 1 as id

Build and see that everything works just fine:

dbt build -s +model_f

Update models/model_f.sql to add {% set ab_values = a_values + b_values %} anywhere within the model defintion:

{% set a_values = british_colours() %}
{% set b_values = american_colors() %}
{% set ab_values = a_values + b_values %}

select 1 as id

Now re-build and see the error:

dbt build -s +model_f
13:12:43  Completed with 1 error and 0 warnings:
13:12:43  
13:12:43    Compilation Error in unit_test test__model_f (models/unit_test.yml)
  'british_colours' is undefined. This can happen when calling a macro that does not exist. Check for typos and/or install package dependencies with "dbt deps".

Relevant log output

See above

Environment

- OS:
- Python:
- dbt:

Which database adapter are you using with dbt?

postgres

Additional Context

Found while researching #10139.

@dbeatty10 dbeatty10 added bug Something isn't working triage unit tests Issues related to built-in dbt unit testing functionality and removed triage labels May 16, 2024
@graciegoheen graciegoheen added the Medium Severity bug with minor impact that does not have resolution timeframe requirement label May 16, 2024
@ChenyuLInx
Copy link
Contributor

Worth confirming would this happen by itself without unittest

@dbeatty10
Copy link
Contributor Author

This works fine for me if I do not have any dbt unit tests defined:

dbt build -s +model_f

But if I add a dbt unit test and re-run that same command, then it gives the error.

@dsillman2000
Copy link

dsillman2000 commented Aug 1, 2024

I can confirm that I'm experiencing this as well.

Context

I'm using dbt-core 1.8.3 with dbt-snowflake 1.8.3 on macOS Ventura 13.6.

I'm developing a custom dbt package which defines a suite of macros. I'm experiencing the error in my package's integration_tests project. I have an example model which calls my_package.my_macro(...) in its logic. I've also written an example unit test for the model to verify its functionality. When running the project with dbt run, the model runs as-expected and the compiled code in target/run and target/compiled reflects the expected macro output.

When running either dbt build or dbt test on the project, however, I get the "macro is not defined" error mentioned above.

Please let us know when you've root-caused this bug, since it will be a huge roadblock for me and my team to pivot to using native DBT unit tests as opposed to the EqualExperts unit testing framework (which doesn't seem to suffer from this bug).

Thanks in advance!

@dbeatty10
Copy link
Contributor Author

Thanks for sharing some of the specifics of your scenario @dsillman2000 👍

If a constant return value is sufficient for the purposes of your unit test, a workaround is to use an overrides configuration like this:

      macros:
        # explicity set star to relevant list of columns
        dbt_utils.star: col_a,col_b,col_c

Otherwise, there isn't a known workaround.

You can stay subscribed to this issue in GitHub to get notified of updates regarding further root cause or resolution.

@Goal1803
Copy link

Goal1803 commented Sep 11, 2024

I am having the same issue,
I have a macros named "test_macro.sql":

{% macro test_macro() %}
{{ return('This is a test macro') }}
{% endmacro %}

in dbt_project.yml I have set up the path correctly and call the macros:

macro-paths: ["macros"]
...
generate_schema_name: "{{ test_macro() }}"

But when I run dbt debug I got this error:

Could not render {{ test_macro() }}: 'test_macro' is undefined

Have anyone firgured out with happened?

@graciegoheen
Copy link
Contributor

@Goal1803 it sounds like you're dealing with a different issue, unrelated to unit tests.

You cannot call a macro directly in the dbt_project.yml as these are parsed at different times. There's a discussion on this here -> #9172

@dsillman2000
Copy link

dsillman2000 commented Sep 30, 2024

Thanks for sharing some of the specifics of your scenario @dsillman2000 👍

If a constant return value is sufficient for the purposes of your unit test, a workaround is to use an overrides configuration like this:

      macros:
        # explicity set star to relevant list of columns
        dbt_utils.star: col_a,col_b,col_c

Otherwise, there isn't a known workaround.

You can stay subscribed to this issue in GitHub to get notified of updates regarding further root cause or resolution.

I'm running into this issue again, in a new project, with a macro defined within the project (more similar to the minimum reproducible example above). Unfortunately, even setting an overrides configuration for the macro does not fix the issue, as it is still complaining that it's unable to find the macro even when I give it a direct, constant override value to return.

I don't know if this should be filed as a separate bug with the overrides configuration not working, since I've been able to override macros in other projects, but not when encountering the "macro not found" bug. Even when defining an override for the "missing" macro, the parser is still unhappy.

"Overrides" section of the subject unit test case:

unit_tests:
  - name: parse_legacy_tool_events
    description: |-
      Shall correctly parse tool events from legacy software versions into a consistent 
      "SupportLogEvent" format.
    model: stg_support_log_tool_events_legacy
    overrides:
      macros:
        legacy_support_log_sw_versions: 'my_constant_value'
    given: ...

After running dbt test:

'legacy_support_log_sw_versions' is undefined. This can happen when calling a macro that does not exist. Check for typos and/or install package dependencies with "dbt deps".

Running the same model with dbt run works fine, since the macro is valid & defined within the project. But it cannot be found during unit testing, and apparently the override does not apply to it.

As with my testimony above, I'm using dbt-core 1.8.3 and dbt-snowflake 1.8.3 macOS Ventura 13.6.

@dsillman2000
Copy link

dsillman2000 commented Sep 30, 2024

Moments after posting above, I had a breakthrough @dbeatty10 ! Please try it in your minimum reproducible example project to see if it works / helps you root cause the issue.

Work-around:

  1. Call the macro inside of a set block, e.g.:
{% set legacy_versions %}{{ legacy_support_log_sw_versions() }}{% endset %}
  1. Reference the previously-set value, instead of calling the macro itself:
select * from {{ source(...) }} where software_version_id in ({{ legacy_versions }}) 
  1. ???
  2. Profit!

Note that this also allows the overrides value to propagate correctly. So the bug must be upstream of the overriding stage of dbt's parser. It's also noteworthy that using the return value of the macro in a set tag (i.e. {% set value = macro_name() %}) does not work, but using the set block syntax does work.

This suggests to me that the broken link must be in how dbt is resolving macros differently in a set block context as opposed to other contexts. Please let me know if you're able to reproduce this work-around in your example case above!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Medium Severity bug with minor impact that does not have resolution timeframe requirement unit tests Issues related to built-in dbt unit testing functionality
Projects
None yet
Development

No branches or pull requests

5 participants