Learning Platform
Глоссарий Troubleshooting
Урок 19.01 · 20 мин
Начальный
Debuggingtarget/manifest.jsonrun_results.jsoncompiled vs run

Когда что-то не работает в dbt, первый рефлекс — гуглить ошибку. Второй — должен быть «открой target/». Эта папка содержит всё, что dbt только что произвёл: финальный SQL, артефакты с метаданными, статусы запусков. Знать, что где лежит, экономит часы.

Жизненный цикл папки target/

target/ создаётся при любой команде dbt (compile, run, test, build, docs generate, …) и перезаписывается каждый раз. То, что лежит в ней после последней команды — это снэпшот этого запуска.

target/
├── compiled/        # SQL после развёртки Jinja (без CREATE TABLE обёртки)
├── run/             # тот же SQL, но обёрнутый в CREATE TABLE / CREATE VIEW
├── manifest.json    # структура всего проекта: модели, тесты, sources, lineage
├── catalog.json     # после `dbt docs generate`: типы колонок, реальные имена в БД
├── run_results.json # после каждого dbt run/test/build: статусы и тайминги
├── partial_parse.msgpack  # кеш парсинга проекта
├── graph.gpickle    # сериализованный граф зависимостей
└── semantic_manifest.json # для семантических метрик
target/: что для чего

Compiled и run — это твой SQL глазами dbt. Manifest и run_results — машинно-читаемые артефакты для интеграций.

compiled/SELECT после Jinja. Можно скопировать в psql
run/CREATE TABLE ... AS (SELECT ...). То, что реально шлётся в БД
manifest.jsonВсе узлы DAG, зависимости, конфиги. Для CI, docs, lineage
run_results.jsonСтатусы последнего запуска. Используется dbt retry

target/compiled/ — финальный SQL без обёртки

Здесь живёт выход Jinja-компиляции: твой SQL, в котором все {{ ref() }}, {{ source() }}, {% set %}, {% for %}, макросы — развёрнуты в строки и значения.

Структура зеркалит models/:

target/compiled/jaffle_shop/
├── models/
│   ├── staging/
│   │   ├── stg_jaffle__customers.sql
│   │   └── stg_jaffle__orders.sql
│   ├── intermediate/
│   │   └── int_order_items_pivoted.sql
│   └── marts/
│       ├── customers.sql
│       └── revenue_daily.sql
├── tests/
│   └── unique_customers_customer_id.sql
└── seeds/...

Открой target/compiled/jaffle_shop/models/marts/customers.sql:

-- было в models/marts/customers.sql:
-- select c.customer_id, c.first_name, ...
-- from {{ ref('stg_jaffle__customers') }} c
-- left join {{ ref('int_order_items_pivoted') }} o ...

-- стало в target/compiled/...:
select c.customer_id, c.first_name, ...
from "jaffle_shop"."main"."stg_jaffle__customers" c
left join "jaffle_shop"."main"."int_order_items_pivoted" o ...

Это главный артефакт для дебага. Скопируй файл целиком в DuckDB shell:

$ duckdb jaffle_shop.duckdb
D> .read target/compiled/jaffle_shop/models/marts/customers.sql

Если SQL работает — проблема в материализации (table vs view, конфиги). Если падает — проблема в самом SQL.

Важно: target/compiled/ не содержит CREATE TABLE — это голый SELECT .... Чтобы увидеть, как именно dbt создаёт таблицу, смотри target/run/.


target/run/ — финальный SQL с CREATE-обёрткой

То же самое, но обёрнутое в нужный DDL по конфигу материализации:

-- target/run/jaffle_shop/models/marts/customers.sql

create or replace table "jaffle_shop"."main"."customers" as (
  select c.customer_id, c.first_name, ...
  from "jaffle_shop"."main"."stg_jaffle__customers" c
  left join "jaffle_shop"."main"."int_order_items_pivoted" o ...
);

Для view-моделей будет CREATE OR REPLACE VIEW .... Для incremental — INSERT INTO ... WHERE NOT EXISTS ... или MERGE.

Когда смотреть сюда:

  • ты подозреваешь, что dbt оборачивает не в то, что ожидал
  • видишь ошибку «materialized view not supported» — а ты конфигурил как table, и хочешь понять, что dbt считает
  • хочешь увидеть точный синтаксис INSERT для инкрементальной модели

target/manifest.json — главный артефакт проекта

manifest.json — это сериализованный весь твой проект: каждая модель, тест, source, snapshot, exposure, со всеми зависимостями, конфигами, описаниями.

Структура (упрощённо):

{
  "metadata": {
    "dbt_version": "1.10.2",
    "generated_at": "2026-05-19T14:35:00Z",
    "project_name": "jaffle_shop"
  },
  "nodes": {
    "model.jaffle_shop.customers": {
      "name": "customers",
      "resource_type": "model",
      "schema": "main",
      "database": "jaffle_shop",
      "config": { "materialized": "table", "tags": ["mart"] },
      "depends_on": {
        "nodes": [
          "model.jaffle_shop.stg_jaffle__customers",
          "model.jaffle_shop.int_order_items_pivoted"
        ]
      },
      "columns": { "customer_id": { ... } },
      "compiled_code": "select ..."
    }
  },
  "sources": { "source.jaffle_shop.jaffle.customers": { ... } },
  "macros": { ... },
  "tests": { ... }
}

Кто его использует:

  • dbt list, dbt docs serve — читают, чтобы построить lineage и страницы.
  • CI с --state ./prod-manifest — сравнивает с baseline для state:modified.
  • dbt Explorer / dbt Cloud — лень-парсит для UI.
  • Внешние инструменты (Datafold, Atlan, Castor) — для каталога метаданных.

Junior туда заглядывает редко, но полезно знать: «если что-то странное с lineage, открой manifest.json, найди узел, посмотри depends_on.nodes».


target/run_results.json — статусы последнего запуска

После каждой команды (run, test, build, seed, …) dbt пишет сюда результат каждого узла:

{
  "metadata": { "generated_at": "2026-05-19T14:35:01Z" },
  "args": {
    "command": "build",
    "select": ["stg_orders+"],
    "target": "dev"
  },
  "results": [
    {
      "unique_id": "model.jaffle_shop.stg_orders",
      "status": "success",
      "execution_time": 0.083,
      "message": null,
      "thread_id": "Thread-2",
      "timing": [
        { "name": "compile", "started_at": "...", "completed_at": "..." },
        { "name": "execute", "started_at": "...", "completed_at": "..." }
      ]
    },
    {
      "unique_id": "test.jaffle_shop.unique_orders_order_id.abc123",
      "status": "fail",
      "execution_time": 0.042,
      "message": "Got 3 results, configured to fail if != 0",
      "failures": 3
    },
    {
      "unique_id": "model.jaffle_shop.customers",
      "status": "skipped",
      "message": "Upstream test failed"
    }
  ]
}

Это источник правды для dbt retry: команда читает этот файл, находит все узлы со status: error или status: skipped, и перезапускает только их + их downstream.

Также используется в CI для метрик: «сколько моделей упало», «сколько строк в среднем в таблицах», «топ-10 самых медленных моделей».


target/catalog.json — только после docs generate

Этот файл не появляется после dbt run. Он создаётся только при dbt docs generate, и содержит реальные имена таблиц, типы колонок, статистики из information_schema warehouse:

{
  "nodes": {
    "model.jaffle_shop.customers": {
      "metadata": {
        "type": "BASE TABLE",
        "schema": "main",
        "name": "customers",
        "database": "jaffle_shop"
      },
      "columns": {
        "customer_id": {
          "type": "INTEGER",
          "index": 1,
          "name": "customer_id"
        },
        "first_name": { "type": "VARCHAR", "index": 2 }
      },
      "stats": {
        "row_count": { "value": 1000 },
        "bytes": { "value": 24576 }
      }
    }
  }
}

Используется dbt docs serve для отображения «реальных» колонок и количества строк в каталоге. Если catalog.json устаревший — на странице будут несоответствия (модель уже изменилась, но catalog показывает старые типы).


partial_parse.msgpack — кеш парсинга

В большом проекте полный парсинг (partial_parse: false) занимает 10-30 секунд. Чтобы быстрее, dbt сохраняет частичный парсинг — какие файлы он уже разобрал, какие конфиги вытащил, и в следующем запуске пере-парсит только изменённые.

Этот файл бинарный (msgpack), напрямую его не читают. Но если у тебя странные «фантомные» ошибки про конфиг, который ты вроде бы исправил — попробуй dbt clean (удаляет target/, включая partial_parse) и запусти заново. Иногда кеш протухает.

Чтобы отключить partial parsing: dbt --no-partial-parse run.


graph.gpickle — DAG в pickle

Сериализованный граф зависимостей в формате Python pickle. Используется внутренне для быстрого вычисления селекторов (особенно +model+, state:modified+). Junior сюда не лезет.


Карта «что куда смотреть»

Где искать ответ на типичный вопрос

Большинство вопросов junior решаются открытием правильного файла в target/. Гуглить — третий шаг.

dbt компилирует не то, что я ожидаюtarget/compiled/<model>.sql
dbt создаёт таблицу не той материализацииtarget/run/<model>.sql
lineage показывает не те зависимостиtarget/manifest.json -> nodes -> depends_on
что упало в последнем билдеtarget/run_results.json -> results
docs serve показывает старые колонкиdbt docs generate (catalog.json regen)
фантомные ошибки конфигаdbt clean -> dbt run --no-partial-parse

Практический пример: дебаг «модель не запускается»

Ситуация: ты пишешь модель, запускаешь dbt run --select my_model, получаешь:

Error: Compilation Error in model my_model (models/my_model.sql)
  'undefined macro' encountered

Шаги:

  1. Открой target/compiled/jaffle_shop/models/my_model.sql.

    • Если файл там есть и SQL выглядит нормально — проблема была в target/run/ обёртке.
    • Если файла нет — компиляция вообще не дошла; смотри logs/dbt.log (об этом следующий урок).
  2. Если SQL в compiled/ корявый — посмотри, какие {{ }} развернулись не так. Возможные причины:

    • macro имеется в проекте, но dbt deps не запускался (пакет не подтянут)
    • макрос определён в другом месте, имя коллизит
    • опечатка в имени макроса
  3. Если SQL валидный, но dbt run падает на DDL — открой target/run/jaffle_shop/models/my_model.sql, увидишь CREATE OR REPLACE TABLE .... Скопируй в DuckDB shell и проверь ошибку базы.

  4. Если что-то странное с state:modified — открой manifest.json и prod-manifest/manifest.json, сравни узел, который должен быть «modified», по полям raw_code или config.


.gitignore — что НЕ коммитим

target/не в git. Тысячи мелких файлов, перезаписываются каждый запуск, никто их не должен видеть, кроме тебя локально и CI:

# .gitignore (стандарт для dbt-проекта)
target/
dbt_packages/
logs/
.user.yml
profiles.yml          # секреты

Единственное исключение: manifest.json в CI коммитят в специальный «production-artifacts»-объект (S3, GitHub artifact) — это нужно для state:modified в PR-CI.


Попробуй сам

В Jaffle Shop:

  1. Запусти dbt compile --select customers. Открой target/compiled/jaffle_shop/models/marts/customers.sql. Найди {{ ref('stg_jaffle__customers') }} в исходнике — посмотри, во что оно развернулось.

  2. Запусти dbt run --select customers. Открой target/run/jaffle_shop/models/marts/customers.sql. Сравни с compiled — увидишь create or replace table ... обёртку.

  3. Запусти dbt build. Открой target/run_results.json. Найди в results секции status каждого узла. Сравни число success, fail, skipped с выводом терминала.

  4. Открой target/manifest.json, найди объект nodes['model.jaffle_shop.customers']. Посмотри его depends_on.nodes — это зависимости через ref().

  5. Запусти dbt docs generate и открой target/catalog.json. Найди nodes['model.jaffle_shop.customers'].columns — увидишь типы реальных колонок из warehouse.


Чек-лист

  • target/compiled/<model>.sql — финальный SELECT, копируй в shell для дебага.
  • target/run/<model>.sql — то же + CREATE-обёртка.
  • target/manifest.json — структура всего проекта; для CI, lineage, интеграций.
  • target/run_results.json — статусы последнего запуска; для retry и метрик.
  • target/catalog.json — реальные колонки из warehouse; только после docs generate.
  • target/partial_parse.msgpack — кеш парсинга; dbt clean если протухло.
  • target/ всегда в .gitignore.
  • В CI manifest.json от main-билда сохраняется в S3 как baseline для PR-CI.
manifest.json в Slim CI
Проверка знанийKnowledge check
Junior дебажит ошибку 'Database error: column "customer_id" does not exist' в модели customers. dbt run падает. Какой алгоритм действий правильный — и почему открывать compiled/ важнее, чем гуглить?
ОтветAnswer
Алгоритм: 1) dbt compile --select customers — это уже создаст target/compiled/.../customers.sql. 2) Открыть этот файл и посмотреть финальный SQL, особенно секции с JOIN и SELECT customer_id. 3) Скопировать SQL в duckdb shell или psql, прогнать вручную. Тогда видна точная позиция ошибки — какая таблица не имеет customer_id, какой алиас, какой JOIN. Гугл может вернуть 50 разных причин, но твоя конкретная проблема — это конкретный SQL, который dbt отправил в БД. Возможно ref() компилируется в правильную таблицу, но без алиаса. Возможно в одной из upstream-моделей колонка переименована, ты не заметил. Возможно используется dbt_utils.star, который не учёл изменение. compiled/ показывает истину — что dbt ДЕЙСТВИТЕЛЬНО собрался отправить, без догадок.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. В чём принципиальная разница между target/compiled/<model>.sql и target/run/<model>.sql?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4