---
title: "aadhar.sh/garage/hidden-flags: Flags the docs don't list"
description: "Nineteen hidden flags in one CLI, and the control that separates an option being accepted from an option doing anything. On a closed schema those are two questions, and the first one is free."
path: "/garage/hidden-flags"
section: "garage"
kind: "content"
updated: "2026-08-24"
source: "https://aadhar.sh/garage/hidden-flags"
---

> Site index: https://aadhar.sh/llms.txt
> Section index: https://aadhar.sh/garage/llms.txt
> This is the Markdown twin of a page on aadhar.sh. The HTML at the source
> URL below is the original, and is hand-written and unminified on purpose.

# Flags the docs don't list

Wrangler 4.125.0 carries nineteen flags marked hidden, so they appear in no help output and no documentation page. Reading them is easy. The hard part is that an option a tool silently ignores and an option it honours produce the same exit code, the same output, and the same success. This page is about the control that separates those two, why it usually costs nothing, and four times the difference decided something real on this site.

## The inventory

Every flag below was pulled out of the shipped bundle by matching option definitions that carry `hidden: true`, then read back with its own description. Filter by what it is for.

Marked rows are the ones that touch this site. The rest are here so the list is the whole list: a survey that reports only the interesting rows cannot tell you how many rows it skipped.

## Two questions, and only one of them is free

When you find an undocumented option, there are two separate things to establish, and reading the docs answers neither.

**Is it accepted?** Does the tool recognise the key at all, or is it dropping an unknown name on the floor. **Does it work?** Does accepting the key change the behaviour the flag claims to change.

The first question is usually free, and that is the part people skip. A tool with strict argument parsing answers it through its exit code alone, with no work performed and nothing deployed:

```
$ wrangler deploy --x-bogus-flag ; echo $?
1
$ wrangler deploy --x-provision=false --dry-run ; echo $?
0
```

Two commands, no account touched, and the answer is decisive: wrangler validates flag names, so a flag it accepts is a flag it knows. Run that before trusting any option a help page omits.

The second question costs a real run, and its answer is worth much less than it looks like when the failure mode is silence.

## When silence is the failure mode

Four cases from this site, each of which cost time in proportion to how late the control was run.

### A payload schema that refuses unknown keys

Cloudflare's Browser Run binding takes a JSON payload. A launch post described selecting a rendering engine with one extra key; the Quick Actions reference did not list it. Sending it answered:

```
{"code":"unrecognized_keys","keys":["browser"]}
```

An invented engine name returned the byte-identical error, which is the useful half of the result. The schema is closed, so it refuses the option rather than failing on the value, and a closed schema is a gift: it answers "is this accepted" for free, every time, with no render performed and no browser minutes spent.

The same feature then produced the opposite trap through the REST door, where the parameter is merely ignored. A 200 came back either way, so the code labelled the render with the engine it had asked for. On a page whose entire premise is showing what a machine actually saw, that label was a claim nobody had checked. It reads `kitesurf-requested` now.

### A compression option three runtimes disagree about

Dictionary compression takes a `dictionary` option. Node 26 honours it. Workers ignore it for zstd and say nothing. Bun ignored it through 1.3.14 and fixed it in [oven-sh/bun#34427](https://github.com/oven-sh/bun/pull/34427). Every one of those failures is silent, because a frame compressed *without* a dictionary still decodes perfectly *with* one. Nothing throws. The only symptom is a byte count that never got smaller.

The control is four lines and it needs no deploy: compress one target three times, with no dictionary, with the right one, and with a deliberately wrong one. An engine that honours the option prints a smaller number for the right dictionary alone. An engine that ignores it prints the same number three times.

| engine | no dictionary | right dictionary | verdict |
| --- | --- | --- | --- |
| node 26 | 70 B | 18 B | honours it |
| workerd | same number three times | ignores it |  |
| bun through 1.3.14 | same number three times | ignored it |  |

Sending the option and reading the exit code would have passed on all three.

### A key that is accepted and still unmeasured

The Browser Run payload takes a `waitForTimeout`. Whether the binding accepts the key was answered for free, using the closed schema above: send it alongside a deliberately invalid URL, and a bogus key comes back as `unrecognized_keys` while an accepted one leaves only the URL error. Three keys passed that test individually and together.

Whether the capture actually waits out the timeout is a different question, it needs a real render, and it is still open. Both halves are written down separately for that reason. An entry claiming the key works, on evidence that only shows it is accepted, is the exact error this page is about.

### A path that routes either way

The engine selector above only functions on one of two URL spellings. Both route. Probed unauthenticated against a real account, each answers `10000 Authentication error` rather than `7003 Could not route to`. So the wrong path costs no error, no retry, and no log line. It costs the feature. One reference page documents the selector on the newer spelling while older pages show the other, so reading either one alone hands you a path that looks right.

## A flag that proves the limit is somewhere else

Among the nineteen is `--max-versions`, on the command that shifts production traffic between Worker versions. This site's release script walks a version to 10%, then 50%, then 100%, and it can only ever name two versions in a step, which shapes the whole procedure: a ramp starting from a three-way split has to drop one of them. The obvious hope is that a hidden flag raises the ceiling. The definition answers it without a single request:

```
"max-versions": {
  hidden: true,
  // experimental, not supported long-term
  describe: "Maximum allowed versions to select",
  type: "number",
  default: 2
  // (when server-side limitation is lifted, we can update this
  //  default or just remove the option entirely)
}
```

The comment is the finding. The cap lives on the server and this flag is the client's mirror of it, so raising the number locally buys an error instead of a wider split. That is a real answer, arrived at by reading rather than by deploying, and it retires a question that had been open on the strength of a guess.

## A flag that looks like the fix and is not one

This site has a documented failure where a gradual deployment splits asset requests: a document served by one version asks for a content-hashed asset only the other version built, and gets a 404. So `--old-asset-ttl`, described as "expire old assets in given seconds rather than immediate deletion", reads like the exact repair.

It is threaded into one place in the entire codebase, and that place is the sync routine for the legacy Workers Sites layer, the retired KV-namespace mechanism that predates the modern assets binding this site uses. The flag would apply to a system that is not running here.

Fifteen minutes of reading, and the answer arrives before any config changes. Had it been adopted on the strength of its description, it would have shipped, changed nothing, and become the fix everyone believed was already in place.

## Pick a situation, get the control

The shape of the doubt decides the experiment. Choose what you are looking at:

## The rule this leaves

On a closed schema, **"is this accepted" and "does this work" are two questions, and the first one is free.** Ask it first, always, because it costs an exit code and it eliminates the most common way an undocumented option wastes a week: being quietly dropped while everything around it reports success.

Then be careful about what a success proves. A 200 from an endpoint that ignores unknown parameters is indistinguishable from a 200 from an endpoint that honoured yours. When you cannot tell those apart, the honest move is to label the result with what you asked for rather than with what you hope happened, and to write the unmeasured half down beside the measured one.

And prefer reading the definition to running the experiment when the definition is in your `node_modules`. Two of the four cases here were settled by a source comment and a call site, in less time than a deploy takes, and neither answer could have been reached by watching the tool succeed.

## What would change this

A tool that accepts unknown flags silently would break the free half outright, and the check for that is the bogus-flag control itself: an exit code of 0 on an invented name means every conclusion on this page has to be re-earned with real runs. A hidden flag becoming documented would move its row from this list to an ordinary reference, which is the outcome to hope for rather than a defeat. And a measurement showing the capture does honour `waitForTimeout` would close the one case here that is deliberately still open.

shipped · the understanding check is part of the page, not a gate

Source: https://aadhar.sh/garage/hidden-flags
