# New in 0.4 | DRE

> Reliable runs and deliveries: exit codes, cancellation and timeouts, run folders, safe uploads, retries, connection checks, Bindings at once, and xlsx styles.

You're reading the docs for DRE 0.4 (v0.4.4). [This page for 0.5](https://getdre.com/docs/new-in-0.4/) · [New in 0.5](https://getdre.com/docs/new-in-0.5/)

# New in 0.4

DRE 0.4 is about runs you can leave to a scheduler: they stop cleanly, say exactly what happened, never leave half a file behind and never send anything twice. It’s a minor release, so a few things change; read [What changes](#what-changes) before you update a scheduled job.

## Readable diagnostics in 0.4.4

0.4.4 keeps paths, hosts and other ordinary settings readable in messages again. Values that `profiles.yml` reads through `env_var()` are masked when they fill a secret field (a password, token, key or other field the plugin marks secret), as are all `DRE_SECRET_*` values. Put a secret that lives inside an ordinary field, such as a URL, in a `DRE_SECRET_*` variable.

## Security hardening in 0.4.3

0.4.3 is a security update; nothing in an existing project needs to change.

-   Connection secrets passed through `env_var()` in `profiles.yml` are now masked in DRE’s output, logs and errors, like `DRE_SECRET_*` values (narrowed to secret fields in 0.4.4).
-   `dre query` is stricter about what a read-only query may do. With the duckdb plugin 1.2.1 or later, its DuckDB sessions are also sandboxed. A read-only database role is still the recommended boundary.
-   Companion installs are verified more strictly and always ask first.
-   String variables in `var_schema` can declare `pattern` and `max_length`.
-   `dre query` and `dre catalog` take `--output-file`; `--output-json` still works there, with a warning, until 0.5.

## Secret masking fixes in 0.4.2

Update to 0.4.2 if you use `DRE_SECRET_*` values. Earlier versions can expose those values in logs or diagnostics after JSON or debug escaping, Markdown escaping, message-title whitespace normalization, or message-summary truncation. History JSON now also redacts registered secrets when reading older run records. The fix covers the CLI and core; existing plugins keep working.

Database inputs and report result files keep their original values, and `mask_secrets: false` continues to disable masking. Review retained logs and run records from earlier versions; if a credential was exposed, rotate it and restrict or remove the affected copies. Updating DRE does not rewrite those historical files.

Thanks to [xingf-msft](https://github.com/xingf-msft) for reporting the JSON text-log bypass in [PR 154](https://github.com/get-dre/dre/pull/154).

## Additive context support in 0.4.1

Optional report descriptions, metadata layers and declared variable schemas let external tools consume report context without changing existing projects. Isolated no-delivery row exports, exact rendered-SQL hashes, live relation catalogs and single-SELECT queries provide generic integration contracts. Companion executables can install separately through the extension registry and receive a `dre mcp` handoff. See [AI-ready reports](https://getdre.com/docs/v0.4/ai-ready-reports/), [manifest contracts](https://getdre.com/docs/v0.4/manifest/#generic-integration-context), and the [commented MCP example](https://github.com/get-dre/dre/tree/master/examples/mcp).

## Runs

-   **[Exit codes](https://getdre.com/docs/v0.4/exit-codes/)** an orchestrator can act on: `0` success, `1` something failed (retry may help), `2` couldn’t start (fix it first), `124` the run’s timeout, `130` Ctrl-C and `143` a termination signal. `dre validate --strict` fails on warnings.
-   **Clean cancellation**: Ctrl-C or a termination signal stops the running query on the server (Postgres, Databricks), records the Binding as `cancelled`, delivers nothing and starts nothing more. A second Ctrl-C stops at once.
-   **Timeouts**: `dre run --timeout 2h` (`DRE_RUN_TIMEOUT`, `flags: run_timeout`) stops a run that takes too long, as `timed_out`. Every plugin that talks to a server has `connect_timeout` and `timeout`, and downloads (the registry, plugins, `dre system update`) give up and try again when nothing arrives (`flags: http_timeout`).
-   **Run folders**: each run of a report and Set gets its own folder under `target/run/`, with its files, `run_results.json` and `dre.log`, and a `current` pointer to the latest. `flags: keep_runs` (`--keep-runs`, `DRE_KEEP_RUNS`) keeps a history; `dre history` lists it, and `dre unlock` clears a run that died. Two runs of the same Binding at once are refused. See [The target path](https://getdre.com/docs/v0.4/target-path/).
-   **[Bindings at once](https://getdre.com/docs/v0.4/connections/#running-bindings-at-once)**: a connection entry’s `threads:` runs that many Bindings on it at once; `dre run --threads N` caps the run.
-   **`dre explain <code>`** describes any [error code](https://getdre.com/docs/v0.4/reference-error-codes/), and every problem DRE reports names its code.

## Deliveries

-   **[No half-written files](https://getdre.com/docs/v0.4/plugin-sftp/)**: `local`, `sftp` and `ftp` upload under a temporary name, then rename (`atomic`, `temp_dir`).
-   **[`if_exists`](https://getdre.com/docs/v0.4/plugins/#a-file-already-at-the-path)** on every file destination: `overwrite` (as before), `error`, or `number` to keep both copies (`report_2.xlsx`).
-   **[Retries](https://getdre.com/docs/v0.4/plugins/#tries-again)** on temporary errors, everywhere, never sending anything twice: `retries` (default 3) on every plugin that talks to a server. A delivery that took several tries has `attempts` in `run_results.json`.
-   **RSA SSH keys** ([RUSTSEC-2023-0071](https://getdre.com/docs/v0.4/plugin-sftp/#rsa-keys)): an RSA key warns once per run; `allow_rsa_keys` silences or refuses it, and `use_agent: true` signs through your SSH agent.

## Checks and configuration

-   **Connection checks**: `dre validate` asks each profile entry’s plugin to check its settings without connecting: a missing field, a value of the wrong form, two settings that can’t go together. `--all-targets` checks every entry. A misspelt key warns, with the nearest key.
-   **`x-*` keys** in every YAML file, for [anchors you reuse](https://getdre.com/docs/v0.4/yaml-reference/#reusing-yaml-x--keys-and-anchors).
-   **Jinja**: `{% break %}` and `{% continue %}`, and maps keep the order they’re written in.
-   **[xlsx](https://getdre.com/docs/v0.4/plugin-xlsx/)** 1.1.0: columns sized from their content (`autofit`, on by default; `width:` per column) and `style:` on the output, a tab or a column (fonts, colours, fills, borders, header and totals rows, banded rows).

## Docs and security

-   One page per plugin, in [Plugins](https://getdre.com/docs/v0.4/plugins/), with its fields and options generated from the plugin itself.
-   Releases carry a CycloneDX SBOM and signed build provenance for every archive and wheel: see [Verifying a download](https://getdre.com/docs/v0.4/install/#verifying-a-download).

## What changes

-   **Exit codes**: a run that couldn’t start (an invalid project or profile, bad flags, a missing plugin) exits `2`, not `1`. A job that treats any non-zero code as a failure is unaffected; one that retries on `1` now won’t retry what retrying can’t fix.
-   **Output files move** into run folders: `target/run/<report>/<set>/runs/<run id>/` instead of `target/run/<report>/<set>/`, with a `current` file naming the latest. Read the path from `run_results.json` or `dre history <report> --latest --path` rather than building it. The shared `logs/dre.log` is gone: each run has its own `dre.log`.
-   **`--var` values are YAML 1.2**: `--var flag=false` is `false` and `--var n=5` a number. Quote a value to keep it text: `--var flag='"false"'`.
-   **Maps iterate in written order** in templates, instead of sorted by key.
-   **Plugins**: DRE 0.4 needs plugins built on protocol 1. Update them all with `dre plugin update` (each `dre.lock` pin moves to the new version): duckdb 1.2.0, postgres 1.3.0, databricks 1.3.0, csv, parquet and fixed\_width 1.0.1, xlsx 1.1.0, object\_store 1.1.0, sftp 1.2.0, ftp 1.1.0, email 1.2.0, slack 1.2.0, teams and google\_chat 1.0.0-rc.2, bigquery and snowflake 1.0.0-alpha.2. An older plugin is refused with the command to update it.
-   **Postgres** `connect_timeout` defaults to 30 seconds (before, no limit).
-   **Skills** 3.0.0 cover DRE 0.4 only.

The schemas for editor checks are at `/schemas/v0.4/`.

[Previous  
New in 0.3](https://getdre.com/docs/v0.4/new-in-0.3/)[Next  
Orchestration recipe](https://getdre.com/docs/v0.4/orchestration/)
