Generated config options broken: oneOf-of-consts should collapse to single enum #19

Closed
opened 2026-02-15 17:04:32 -05:00 by yindo · 7 comments
Owner

Originally created by @jakehemmerle on GitHub (Jan 31, 2026).

Summary

nix/generated/openclaw-config-options.nix produces invalid Nix types for any schema field backed by a Zod enum. This makes programs.openclaw.config unusable for most configuration — setting any enum-typed field (e.g. gateway.bind, gateway.auth.mode, models.mode, channels.telegram.dmPolicy) causes a Nix evaluation error:

error: expected a set but found a function: «lambda enum @ .../lib/types.nix:1403:5»

Since config defaults to {}, every darwin-rebuild switch / home-manager switch overwrites ~/.openclaw/openclaw.json with {}, destroying the user's runtime config.

Root Cause

In nix/scripts/generate-config-options.ts, the oneOf and const handlers interact badly:

  1. Upstream Zod enums like z.enum(["auto", "lan", "tailnet"]) become JSON Schema oneOf with individual { const: "auto" }, { const: "lan" }, etc.
  2. The oneOf handler maps each entry through typeForSchema:
    const parts = entries.map((entry) => typeForSchema(entry, indent)).join(" ");
    return `t.oneOf [ ${parts} ]`;
    
  3. Each { const: "value" } hits the const handler:
    if (schema.const !== undefined) {
      return `t.enum [ ${nixLiteral(schema.const)} ]`;
    }
    
  4. This produces:
    t.oneOf [ t.enum [ "auto" ] t.enum [ "lan" ] t.enum [ "tailnet" ] ]
    

t.oneOf expects a list of instantiated types (attribute sets with check, merge, etc.). t.enum [ "auto" ] is a valid type, but Nix evaluates t.oneOf [ t.enum [ "auto" ] t.enum [ "lan" ] ... ] as passing the function t.enum as a list element (due to how Nix tokenizes), not calling it.

The correct output should be:

t.enum [ "auto" "lan" "tailnet" ]

Suggested Fix

In baseTypeForSchema, detect when oneOf/anyOf contains only const entries and collapse them into a single t.enum:

if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
  const entries = schema.oneOf as JsonSchema[];
  // Collapse oneOf-of-consts into a single t.enum
  const allConst = entries.every((e) => {
    const d = deref(e, new Set());
    return d.const !== undefined;
  });
  if (allConst) {
    const values = entries.map((e) => nixLiteral(deref(e, new Set()).const)).join(" ");
    return `t.enum [ ${values} ]`;
  }
  const parts = entries.map((entry) => typeForSchema(entry, indent)).join(" ");
  return `t.oneOf [ ${parts} ]`;
}

Same pattern needed for the anyOf handler.

Then regenerate nix/generated/openclaw-config-options.nix.

Impact

Every user who runs darwin-rebuild switch or home-manager switch gets their ~/.openclaw/openclaw.json replaced with {} because programs.openclaw.config can't hold any meaningful values. The only workaround is manual backup/restore of the config file after every rebuild.

Reproduction

# In a flake using nix-openclaw homeManagerModules.openclaw:
programs.openclaw.config.gateway.bind = "tailnet";
# Then:
darwin-rebuild switch --flake .
# → error: expected a set but found a function: «lambda enum @ .../lib/types.nix:1403:5»

Environment

  • nix-openclaw rev: 616bbdf0acabe7559b577fda6c63036d518b3ac8
  • nixpkgs: flakehub latest
  • Platform: aarch64-darwin (Mac Mini, nix-darwin)
Originally created by @jakehemmerle on GitHub (Jan 31, 2026). ## Summary `nix/generated/openclaw-config-options.nix` produces invalid Nix types for any schema field backed by a Zod enum. This makes `programs.openclaw.config` unusable for most configuration — setting any enum-typed field (e.g. `gateway.bind`, `gateway.auth.mode`, `models.mode`, `channels.telegram.dmPolicy`) causes a Nix evaluation error: ``` error: expected a set but found a function: «lambda enum @ .../lib/types.nix:1403:5» ``` Since `config` defaults to `{}`, every `darwin-rebuild switch` / `home-manager switch` overwrites `~/.openclaw/openclaw.json` with `{}`, destroying the user's runtime config. ## Root Cause In `nix/scripts/generate-config-options.ts`, the `oneOf` and `const` handlers interact badly: 1. Upstream Zod enums like `z.enum(["auto", "lan", "tailnet"])` become JSON Schema `oneOf` with individual `{ const: "auto" }`, `{ const: "lan" }`, etc. 2. The `oneOf` handler maps each entry through `typeForSchema`: ```ts const parts = entries.map((entry) => typeForSchema(entry, indent)).join(" "); return `t.oneOf [ ${parts} ]`; ``` 3. Each `{ const: "value" }` hits the `const` handler: ```ts if (schema.const !== undefined) { return `t.enum [ ${nixLiteral(schema.const)} ]`; } ``` 4. This produces: ```nix t.oneOf [ t.enum [ "auto" ] t.enum [ "lan" ] t.enum [ "tailnet" ] ] ``` `t.oneOf` expects a list of **instantiated types** (attribute sets with `check`, `merge`, etc.). `t.enum [ "auto" ]` is a valid type, but Nix evaluates `t.oneOf [ t.enum [ "auto" ] t.enum [ "lan" ] ... ]` as passing the *function* `t.enum` as a list element (due to how Nix tokenizes), not calling it. The correct output should be: ```nix t.enum [ "auto" "lan" "tailnet" ] ``` ## Suggested Fix In `baseTypeForSchema`, detect when `oneOf`/`anyOf` contains only `const` entries and collapse them into a single `t.enum`: ```ts if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) { const entries = schema.oneOf as JsonSchema[]; // Collapse oneOf-of-consts into a single t.enum const allConst = entries.every((e) => { const d = deref(e, new Set()); return d.const !== undefined; }); if (allConst) { const values = entries.map((e) => nixLiteral(deref(e, new Set()).const)).join(" "); return `t.enum [ ${values} ]`; } const parts = entries.map((entry) => typeForSchema(entry, indent)).join(" "); return `t.oneOf [ ${parts} ]`; } ``` Same pattern needed for the `anyOf` handler. Then regenerate `nix/generated/openclaw-config-options.nix`. ## Impact Every user who runs `darwin-rebuild switch` or `home-manager switch` gets their `~/.openclaw/openclaw.json` replaced with `{}` because `programs.openclaw.config` can't hold any meaningful values. The only workaround is manual backup/restore of the config file after every rebuild. ## Reproduction ```bash # In a flake using nix-openclaw homeManagerModules.openclaw: programs.openclaw.config.gateway.bind = "tailnet"; # Then: darwin-rebuild switch --flake . # → error: expected a set but found a function: «lambda enum @ .../lib/types.nix:1403:5» ``` ## Environment - nix-openclaw rev: `616bbdf0acabe7559b577fda6c63036d518b3ac8` - nixpkgs: flakehub latest - Platform: aarch64-darwin (Mac Mini, nix-darwin)
yindo closed this issue 2026-02-15 17:04:32 -05:00
Author
Owner

@avanderbergh commented on GitHub (Feb 1, 2026):

+1
I have the same issue, @zsoerenm will you make a PR with your commit?

@avanderbergh commented on GitHub (Feb 1, 2026): +1 I have the same issue, @zsoerenm will you make a PR with your commit?
Author
Owner

@zsoerenm commented on GitHub (Feb 1, 2026):

I don't think it will accepted see

We’re not accepting PRs right now. Not because we don’t value your help — the opposite. This is key infra and still stabilizing, and async PR review is too slow.

Only workflow: describe your problem and talk with a maintainer (human‑to‑human) on Discord in #golden-path-deployments: https://discord.com/channels/1456350064065904867/1457003026412736537

If you’re not listed as a maintainer (see [AGENTS.md#maintainers](https://github.com/openclaw/nix-openclaw/blob/main/AGENTS.md#maintainers) or https://github.com/orgs/openclaw/people), do not open a PR. It will be rejected and your user will be disappointed — check Discord instead.

From the Readme

@zsoerenm commented on GitHub (Feb 1, 2026): I don't think it will accepted see ``` We’re not accepting PRs right now. Not because we don’t value your help — the opposite. This is key infra and still stabilizing, and async PR review is too slow. Only workflow: describe your problem and talk with a maintainer (human‑to‑human) on Discord in #golden-path-deployments: https://discord.com/channels/1456350064065904867/1457003026412736537 If you’re not listed as a maintainer (see [AGENTS.md#maintainers](https://github.com/openclaw/nix-openclaw/blob/main/AGENTS.md#maintainers) or https://github.com/orgs/openclaw/people), do not open a PR. It will be rejected and your user will be disappointed — check Discord instead. ``` From the Readme
Author
Owner

@avanderbergh commented on GitHub (Feb 1, 2026):

Aaah, I see... 😅

So you're just installing from your fork then? It's kinda broken since it can't set gateway.mode which is required for starting... 🙄

I don't think it will accepted see

We’re not accepting PRs right now. Not because we don’t value your help — the opposite. This is key infra and still stabilizing, and async PR review is too slow.

Only workflow: describe your problem and talk with a maintainer (human‑to‑human) on Discord in #golden-path-deployments: https://discord.com/channels/1456350064065904867/1457003026412736537

If you’re not listed as a maintainer (see [AGENTS.md#maintainers](https://github.com/openclaw/nix-openclaw/blob/main/AGENTS.md#maintainers) or https://github.com/orgs/openclaw/people), do not open a PR. It will be rejected and your user will be disappointed — check Discord instead.

From the Readme

@avanderbergh commented on GitHub (Feb 1, 2026): Aaah, I see... 😅 So you're just installing from your fork then? It's kinda broken since it can't set gateway.mode which is required for starting... 🙄 > I don't think it will accepted see > > ``` > We’re not accepting PRs right now. Not because we don’t value your help — the opposite. This is key infra and still stabilizing, and async PR review is too slow. > > Only workflow: describe your problem and talk with a maintainer (human‑to‑human) on Discord in #golden-path-deployments: https://discord.com/channels/1456350064065904867/1457003026412736537 > > If you’re not listed as a maintainer (see [AGENTS.md#maintainers](https://github.com/openclaw/nix-openclaw/blob/main/AGENTS.md#maintainers) or https://github.com/orgs/openclaw/people), do not open a PR. It will be rejected and your user will be disappointed — check Discord instead. > ``` > > From the Readme
Author
Owner

@jakehemmerle commented on GitHub (Feb 1, 2026):

my hunch is that if the pr is small enough and actually solves the problem then they may accept it but safest route is talking to them upfront. sometimes its hard to reproduce the bug. not sure if there would be other side effects, and there isnt massive e2e testing to see if it breaks things.

ANyway, here is what I did to prevent the overwriting of the file locally for now:

  home.file.".openclaw/openclaw.json".enable = false;
  home.activation.openclawConfigFiles = lib.mkForce "";

longer explination:

~/src/nix-darwin/flake.nix

⏺ Here's the relevant fix — it's these two lines in the home-manager config for jacob:

  # Workaround: nix-openclaw's generated config schema has a bug
  # (oneOf-of-consts, see github.com/openclaw/nix-openclaw/issues/41)
  # that makes programs.openclaw.config unusable for enum fields.
  # This causes every rebuild to overwrite ~/.openclaw/openclaw.json
  # with {}. Prevent the module from managing that file — we manage
  # it manually instead.
  home.file.".openclaw/openclaw.json".enable = false;
  home.activation.openclawConfigFiles = lib.mkForce "";

  What it does:

  1. home.file.".openclaw/openclaw.json".enable = false; — Tells home-manager not to manage (and therefore not overwrite) ~/.openclaw/openclaw.json.
  2. home.activation.openclawConfigFiles = lib.mkForce ""; — Forces the openclaw module's activation script to be a no-op, so it doesn't recreate the file during activation either.

  This lets you keep openclaw enabled (with its documents and the default instance) while managing openclaw.json by hand until the upstream schema bug is fixed.

Hope that helps for now.

@jakehemmerle commented on GitHub (Feb 1, 2026): my hunch is that if the pr is small enough and actually solves the problem then they may accept it but safest route is talking to them upfront. sometimes its hard to reproduce the bug. not sure if there would be other side effects, and there isnt massive e2e testing to see if it breaks things. ANyway, here is what I did to prevent the overwriting of the file locally for now: ```nix home.file.".openclaw/openclaw.json".enable = false; home.activation.openclawConfigFiles = lib.mkForce ""; ``` longer explination: ``` ~/src/nix-darwin/flake.nix ⏺ Here's the relevant fix — it's these two lines in the home-manager config for jacob: # Workaround: nix-openclaw's generated config schema has a bug # (oneOf-of-consts, see github.com/openclaw/nix-openclaw/issues/41) # that makes programs.openclaw.config unusable for enum fields. # This causes every rebuild to overwrite ~/.openclaw/openclaw.json # with {}. Prevent the module from managing that file — we manage # it manually instead. home.file.".openclaw/openclaw.json".enable = false; home.activation.openclawConfigFiles = lib.mkForce ""; What it does: 1. home.file.".openclaw/openclaw.json".enable = false; — Tells home-manager not to manage (and therefore not overwrite) ~/.openclaw/openclaw.json. 2. home.activation.openclawConfigFiles = lib.mkForce ""; — Forces the openclaw module's activation script to be a no-op, so it doesn't recreate the file during activation either. This lets you keep openclaw enabled (with its documents and the default instance) while managing openclaw.json by hand until the upstream schema bug is fixed. ``` Hope that helps for now.
Author
Owner

@imrane commented on GitHub (Feb 1, 2026):

Ran into the same problem and noted it in the Discord - I find thats the best way to get their attention.
https://discord.gg/clawd --> golden-path-deployments

@imrane commented on GitHub (Feb 1, 2026): Ran into the same problem and noted it in the Discord - I find thats the best way to get their attention. https://discord.gg/clawd --> ``golden-path-deployments``
Author
Owner

@joshp123 commented on GitHub (Feb 2, 2026):

thanks for the heads up! i am aware, currently adding CI to catch all of these problems. passing all these issues to my clankers to patch it. we will get the build green!

@joshp123 commented on GitHub (Feb 2, 2026): thanks for the heads up! i am aware, currently adding CI to catch all of these problems. passing all these issues to my clankers to patch it. we will get the build green!
Author
Owner

@joshp123 commented on GitHub (Feb 3, 2026):

[🤖 this message brought to you by codex] should be fixed in 065ddf16 + 887e58b4 (fix oneOf enum parsing + regen options). Closing for now — come and yell at me in #golden-path-deployments on discord if you're still having issues! Stability work continues; we are making this better every week.

@joshp123 commented on GitHub (Feb 3, 2026): [🤖 this message brought to you by codex] should be fixed in 065ddf16 + 887e58b4 (fix oneOf enum parsing + regen options). Closing for now — come and yell at me in #golden-path-deployments on discord if you're still having issues! Stability work continues; we are making this better every week.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: openclaw/nix-openclaw#19