# Troubleshooting

> Common failure modes: overwrite protection, unpack directory skip behavior, UnpackWarningKind codes, TDZ and parse-recovery warnings, formatter failures, and bug report fields.

- Repository: pionxzh/wakaru
- GitHub: https://github.com/pionxzh/wakaru
- Human docs: https://grok-wiki.com/public/docs/pionxzh-wakaru-77a438a6cc6b
- Complete Markdown: https://grok-wiki.com/public/docs/pionxzh-wakaru-77a438a6cc6b/llms-full.txt

## Source Files

- `README.md`
- `crates/core/src/driver/types.rs`
- `crates/core/src/tdz_check.rs`
- `docs/debugging.md`
- `.github/ISSUE_TEMPLATE/bug_report.yml`

---

---
title: Troubleshooting
description: Common failure modes — overwrite protection, unpack directory skip behavior, UnpackWarningKind codes, TDZ and parse-recovery warnings, formatter failures, and bug report fields.
---

Wakaru is designed to produce output even when individual modules fail: warnings are collected, raw code is preserved where transforms cannot complete, and the CLI exits non-zero only when at least one **error-severity** warning is present. This page maps symptoms to causes and shows what to include in a bug report.

## Quick symptom map

| Symptom | Likely cause | First step |
|---------|--------------|------------|
| `output file … already exists` | Overwrite protection | Add `--force` or choose a new `-o` path |
| `output directory … is not empty` | Non-empty unpack target | Add `--force` or use an empty directory |
| `no bundle or chunk files detected` | Directory scan found no bundles | Pass explicit bundle files, or see [Unpack bundles](/unpack-bundles) |
| `scanned: N … skipped: M` with low `detected` | Plain JS files in a `dist/` tree | Expected — only bundle/chunk shapes are unpacked |
| `error: … tdz_violation` | Transform reordered `let`/`const`/`class` | Run with `--diagnostics`; try `--level minimal` |
| `warning: oxc formatter failed` | Emitted code is not parseable by the formatter | Inspect decompiled output; file a bug with `--diagnostics` |
| `errors in N module(s)` at end | Non-diagnostic warning kinds | Inspect stderr or `--json` warnings where `is_error` is true |
| Internal panic with GitHub link | Unhandled Rust panic | Use the pre-filled issue URL from stderr |

## Overwrite protection

Wakaru refuses to clobber existing outputs unless you pass `--force`. This applies globally to decompile, unpack, `extract`, and `debug trace`.

<ParamField body="--force" type="flag">
Overwrite existing output **files** and write into **non-empty** output directories. Without it, Wakaru exits before processing.
</ParamField>

### Single-file decompile

When `-o output.js` points to a file that already exists:

```text
output file output.js already exists; pass --force to overwrite
```

<Steps>
<Step title="Choose a safe output path">

Run without `-o` to print to stdout, or pick a path that does not exist yet.

</Step>
<Step title="Or pass --force">

```bash
wakaru input.js -o output.js --force
```

</Step>
</Steps>

### Unpack to a directory

When `-o out/` exists and is not empty:

```text
output directory out/ is not empty; pass --force to write into it
```

With `--force` on a non-empty directory, Wakaru uses a **write-if-changed** fast path: files whose bytes are identical to the new output are left untouched (no redundant writes or timestamp updates). Changed files are overwritten.

```bash
wakaru bundle.js --unpack -o out/ --force
```

### Other subcommands

`wakaru extract` and `wakaru debug trace` (hidden) use the same `ensure_output_file` / `ensure_output_dir` checks. Pass `--force` when re-running against an existing target.

## Unpack directory skip behavior

Directory inputs work **only** with `--unpack`. Wakaru recursively scans for candidates, then keeps only files that match a bundle or chunk shape.

### What gets scanned

- **Extensions:** `.js`, `.mjs`, `.cjs`
- **Skipped entirely:** hidden files and directories (names starting with `.`), `node_modules` trees, non-JS extensions (e.g. `.js.map`, `.ts`)

### What gets kept vs skipped

Each scanned candidate is tested with `is_detected_unpack_input`. Files that do not match a bundle/chunk shape are **skipped** — they are not copied, decompiled, or written to the output directory.

On a TTY, stderr reports scan statistics:

```text
scanned: 4 file(s), detected: 2 bundle/chunk file(s), skipped: 2 file(s)
```

| Counter | Meaning |
|---------|---------|
| `scanned` | JS-like files read and evaluated |
| `detected` | Files accepted as bundle/chunk inputs |
| `skipped` | Scanned files that failed bundle detection |

### Directory vs explicit file inputs

| Input mode | Non-bundle `.js` behavior |
|------------|---------------------------|
| **Directory** (`dist/ --unpack`) | Skipped silently (counted in `skipped`) |
| **Explicit file** (`plain.js --unpack`) | Still processed — normal unpack fallback applies |

If a directory scan finds zero detected bundles:

```text
no bundle or chunk files detected in directory input
```

<Steps>
<Step title="Confirm bundles are present">

Point at the actual webpack chunk, runtime entry, or browserify standalone — not only application source files sitting beside bundles.

</Step>
<Step title="Try explicit file paths">

```bash
wakaru entry.js chunk.123.js --unpack -o out/
```

</Step>
<Step title="Adjust detection mode">

Use `--unpack=strict` for structural detection only, or default `--unpack` / `--unpack=auto` to allow heuristic scope-hoisted splitting. See [Bundle formats and unpacking](/bundle-formats-and-unpacking).

</Step>
</Steps>

### Unsafe module filenames

During unpack, module filenames are resolved under the output directory. Paths that escape the output root (e.g. `../outside.js` or symlink tricks) are rejected:

```text
unsafe module filename "../evil.js": path escapes output directory
```

This is intentional path-traversal protection, not a decompiler bug.

## Warning kinds (`UnpackWarningKind`)

Warnings flow through the core API, CLI stderr, `--json` output, and the WASM bindings (with one extra kind — see [Formatter failures](#formatter-failures)).

### Severity model

<ResponseField name="is_diagnostic" type="boolean">
`true` for kinds that signal potential transform issues but **do not** fail the run. The CLI still exits 0 unless an error-severity warning is present.
</ResponseField>

<ResponseField name="is_error" type="boolean">
`true` when `!is_diagnostic`. Triggers `has_errors()`, a non-zero CLI exit, and the `errors in N module(s)` summary.
</ResponseField>

### Full kind reference

| Kind string | Severity | When it fires | Output preserved? |
|-------------|----------|---------------|-------------------|
| `raw_normalization_failed` | Error* | Raw unpack normalization could not parse a module | Yes — unparsed raw code kept |
| `fact_collection_parse_failed` | Error | Phase 1 fact collection could not parse a module | Yes — empty facts, pipeline continues |
| `decompile_failed` | Error | Phase 2 rule pipeline returned an error for a module | Yes — raw extracted code kept |
| `input_parse_recovered` | Diagnostic | Input parsed with recoverable SWC errors (`--diagnostics`) | Yes |
| `tdz_violation` | Diagnostic | Reference to `let`/`const`/`class` before declaration (`--diagnostics`) | Yes |
| `duplicate_declaration` | Error | Duplicate lexical binding in same scope (`--diagnostics`) | Yes |
| `import_cycle` | Diagnostic | Local import SCC not merged (size/safety limits) (`--diagnostics`) | Yes |
| `output_parse_recovered` | Error | Emitted code parsed with recoverable errors (`--diagnostics`) | Yes |
| `output_parse_failed` | Error | Emitted code is entirely unparseable (`--diagnostics`) | Yes — broken code still written |

\*`raw_normalization_failed` is recorded only when `--diagnostics` is enabled on the raw/heuristic normalization path. `fact_collection_parse_failed` and `decompile_failed` are always recorded during full unpack.

### JSON shape

With `--json`, each warning includes machine-readable severity:

<RequestExample>
```bash
wakaru bundle.js --unpack --diagnostics --json -o out/
```
</RequestExample>

<ResponseExample>
```json
{
  "warnings": [
    {
      "filename": "module-1.js",
      "kind": "tdz_violation",
      "is_error": false,
      "message": "reference to `x` before declaration"
    }
  ],
  "failed": 0,
  "total": 12,
  "elapsed_ms": 340
}
```
</ResponseExample>

See [JSON output and CI](/json-output-and-ci) for the full schema and piping patterns.

### Which warnings require `--diagnostics`

`DecompileOptions::diagnostics` defaults to `false`. The CLI flag `--diagnostics` sets it.

| Kind | Without `--diagnostics` | With `--diagnostics` |
|------|-------------------------|----------------------|
| `fact_collection_parse_failed` | Reported | Reported |
| `decompile_failed` | Reported | Reported |
| `tdz_violation` | Silent | Reported |
| `input_parse_recovered` | Silent | Reported |
| `duplicate_declaration` | Silent | Reported |
| `import_cycle` | Silent | Reported |
| `output_parse_recovered` / `output_parse_failed` | Silent | Reported |
| `raw_normalization_failed` | Silent | Reported (raw path) |

For bug reports and CI quality gates, always rerun with `--diagnostics` (and `--json` for automation).

## TDZ violations

Temporal dead zone (TDZ) checking runs on the **transformed AST** after the rule pipeline, using traversal order rather than source spans. This catches cases where rules reorder nodes without updating byte positions.

### What is detected

- References to `let`, `const`, or `class` bindings before their declaration in the same scope
- Self-references in initializers (`const x = x`)
- Class heritage references before the base binding (`class Foo extends Bar` before `let Bar`)
- Parameter default expressions referencing later parameters
- Destructuring default ordering (later defaults may reference earlier bindings; self-reference is still TDZ)

Nested functions and arrows are **not** checked against outer declarations (deferred execution).

### Example

<Input>
```javascript
console.log(x);
let x = 1;
```
</Input>

With `--diagnostics`:

```text
warning: module.js: reference to `x` before declaration
```

### What to do

<AccordionGroup>
<Accordion title="TDZ warning after an upgrade">

1. Reproduce with `--level minimal` to see if aggressive heuristics caused the reorder.
2. Use [Trace the rule pipeline](/trace-rule-pipeline) to find which rule introduced the bad ordering.
3. File a bug with the minimal input, command, and `--diagnostics` output.

</Accordion>
<Accordion title="TDZ in unpack but not single-file">

Unpack uses the two-phase fact pipeline. Trace the **extracted module** as a single file — `debug trace` on the whole bundle is misleading. See [Debug regressions](/debug-regressions).

</Accordion>
</AccordionGroup>

## Parse-recovery warnings

Wakaru uses SWC's recoverable parse mode in several places. Recovery lets the pipeline continue, but diagnostics flag suspect input or output.

### `input_parse_recovered`

Fires when the **input** to decompile/unpack had recoverable parse errors. Message prefix:

```text
input parse recovered from parser error: …
```

The transform pipeline still runs on the recovered AST.

### `output_parse_recovered` and `output_parse_failed`

After emit, `verify_output_parses` re-parses the **output** code (only with `--diagnostics`).

| Kind | Meaning |
|------|---------|
| `output_parse_recovered` | Output has recoverable parse issues — **error severity** |
| `output_parse_failed` | Output is wholly unparseable — **error severity** |

Both kinds cause a non-zero exit when `--diagnostics` is on, even though the (possibly broken) code is still written.

### `duplicate_declaration`

Separate from parse recovery: detects duplicate `let`/`const`/`class`/import bindings in the same lexical scope. Error severity under `--diagnostics`.

## Formatter failures

`--formatter` runs a final **oxc** formatting pass after decompilation. Formatting is off by default.

### CLI behavior

When oxc cannot format the emitted code, Wakaru **preserves the unformatted output** and prints a stderr warning:

```text
warning: oxc formatter failed for module.js, preserving output: …
```

Formatter failures do **not** cause a non-zero exit in the CLI. The decompiled code is still written.

### WASM / playground behavior

The WASM bindings surface formatter failures as a distinct warning kind not present in `UnpackWarningKind`:

| Kind | Surface |
|------|---------|
| `formatter_failed` | WASM and TypeScript types only |

Message shape:

```text
oxc formatter failed, preserving output: …
```

### When formatting fails

Formatting fails when the **emitted** JavaScript is syntactically invalid for oxc — often the same underlying issue as `output_parse_failed`. If you see formatter warnings:

1. Inspect the raw emitted code (disable `--formatter` to see pre-format output).
2. Rerun with `--diagnostics` to get `output_parse_*` warnings from the core pipeline.
3. File a bug — the root cause is usually a rule emit bug, not the formatter itself.

```bash
wakaru input.js --diagnostics -o output.js
wakaru input.js --formatter --diagnostics -o output.js
```

## Other CLI validation errors

| Error | Cause |
|-------|-------|
| `--unpack requires -o/--output` | Unpack always needs an output directory |
| `cannot decompile a directory` | Single-file mode received a directory — add `--unpack` |
| `multiple input files require --unpack` | Pass several files only with `--unpack` |
| `--source-map is only supported with a single input file` | Source maps apply to one input at a time |
| `no input specified` | No file argument and stdin is a TTY |
| `output path … exists and is not a directory` | `-o` for unpack must be a directory |
| Panic + GitHub issue URL | Unhandled internal error — use the pre-filled link |

## Exit codes and stderr labels

On a TTY, warnings print as `warning:` and errors as `error:` (styled when color is enabled). With `--json`, human stderr summaries are suppressed; warnings live in the JSON object.

Unpack summary line when modules fail:

```text
total: 12 module(s) (3 failed) in 1.24s
```

Followed by:

```text
errors in 3 module(s): chunk-1.js, chunk-4.js, vendor.js
```

Single-file decompile uses the same `errors in N module(s)` pattern when `has_errors()` is true.

## Filing a bug report

Use the GitHub **Decompiler Bug Report** template. Required and recommended fields:

| Field | Required | What to provide |
|-------|----------|-----------------|
| Describe the bug | Yes | What you ran, what you expected, what happened |
| Expected behavior | Yes | Correct or desired output behavior |
| Version | No | Output of `wakaru --version` or npm package version |
| Command used | No | Full command; add `--diagnostics` for extra warnings |
| Input code | No | Minimal JS sample, or playground / gist link |
| Reproduction | No | Playground URL or gist — minimal repro strongly preferred |
| Steps to reproduce | No | Build steps, bundler version, flags |
| Actual behavior | No | Paste stderr, `--json` warnings, or bad output |

<Steps>
<Step title="Minimize the input">

Reduce to the smallest file or module that still shows the problem. For bundles, extract one failing module if possible.

</Step>
<Step title="Capture the exact command">

```bash
wakaru bundle.js --unpack --diagnostics --level standard -o out/ 2>stderr.txt
```

</Step>
<Step title="Include both bad and expected output">

Paste the failing module from `out/` and describe what readable structure you expected.

</Step>
<Step title="For panics">

Copy the full panic output. The CLI prints a pre-filled issue URL with version and OS.

</Step>
</Steps>

For contributor-side regression investigation, see [Debug regressions](/debug-regressions) and [Trace the rule pipeline](/trace-rule-pipeline).

## Related pages

<CardGroup>
<Card title="Unpack bundles" href="/unpack-bundles">
Operational guide for `--unpack` modes, directory scanning, and `--force`.
</Card>
<Card title="JSON output and CI" href="/json-output-and-ci">
Warning `kind` strings, `is_error`, and automation patterns.
</Card>
<Card title="CLI reference" href="/cli-reference">
Full flag surface including `--diagnostics`, `--formatter`, and `--force`.
</Card>
<Card title="Debug regressions" href="/debug-regressions">
Rule trace bisection, snapshot layers, and symptom-to-cause mapping.
</Card>
<Card title="Core API reference" href="/core-api-reference">
`UnpackWarningKind`, `has_errors()`, and `DecompileOptions::diagnostics`.
</Card>
</CardGroup>
