Summary
When a user sets BOTH agents.<name>.discord.botToken (or .slack.botToken / .slack.appToken / .stt.apiKey / .gateway.token) AND the same key in agents.<name>.env.*, the rendered Deployment ends up with duplicate env entries for the same key. Kubernetes rejects the apply:
failed to create typed patch object (default/openab-claude; apps/v1, Kind=Deployment): errors:
.spec.template.spec.containers[name="openab"].env: duplicate entries for key [name="DISCORD_BOT_TOKEN"]
.spec.template.spec.containers[name="openab"].env: duplicate entries for key [name="SLACK_BOT_TOKEN"]
Chart 0.8.2, k8s 1.32 (OrbStack), helm 3.18.x.
Why users hit this
Per the existing workaround for agent-subprocess env isolation (see related #699), users have to re-declare bot tokens in agents.<name>.env.* so the subprocess can read them. But they also need to keep discord.botToken / slack.botToken set so the chart's other paths (secret.yaml, etc.) work. Both paths feed the Deployment's env: array, creating duplicates.
Concrete helm-install.sh pattern that triggers the bug:
helm upgrade --install openab openab/openab \
-f values.yaml \
--set agents.claude.discord.botToken="$CLAUDE_DISCORD_BOT_TOKEN" \
--set agents.claude.slack.botToken="$CLAUDE_SLACK_BOT_TOKEN" \
--set-string agents.claude.env.DISCORD_BOT_TOKEN="$CLAUDE_DISCORD_BOT_TOKEN" \
--set-string agents.claude.env.SLACK_BOT_TOKEN="$CLAUDE_SLACK_BOT_TOKEN"
The chart's templates/deployment.yaml lines 44-65 auto-promote .discord.botToken / .slack.botToken / .slack.appToken / .stt.apiKey / .gateway.token into container env via valueFrom.secretKeyRef. Lines 82-85 then loop $cfg.env and emit each key as inline value:. Same key, two entries.
Repro
values:
agents:
claude:
discord:
botToken: <any-token>
slack:
enabled: true
botToken: <any-token>
env:
DISCORD_BOT_TOKEN: <same-token>
SLACK_BOT_TOKEN: <same-token>
Run helm upgrade --install ... → apply fails with duplicate-key.
Proposed fix (chart-side, minimal)
In templates/deployment.yaml, guard each auto-promotion block with a hasKey check against agents.<name>.env. When the user explicitly sets the env var, skip the secretKeyRef auto-promotion (the explicit value wins).
Diff:
env:
+ {{- $explicitEnv := $cfg.env | default dict }}
- {{- if and (ne (toString ($cfg.discord).enabled) "false") ($cfg.discord).botToken }}
+ {{- if and (ne (toString ($cfg.discord).enabled) "false") ($cfg.discord).botToken (not (hasKey $explicitEnv "DISCORD_BOT_TOKEN")) }}
- name: DISCORD_BOT_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "openab.agentFullname" $d }}
key: discord-bot-token
{{- end }}
- {{- if and ($cfg.slack).enabled ($cfg.slack).botToken }}
+ {{- if and ($cfg.slack).enabled ($cfg.slack).botToken (not (hasKey $explicitEnv "SLACK_BOT_TOKEN")) }}
- name: SLACK_BOT_TOKEN
...
{{- end }}
{{- /* same hasKey guard added to SLACK_APP_TOKEN, STT_API_KEY, GATEWAY_WS_TOKEN */ -}}
Verified locally against chart 0.8.2 — patched deployment.yaml renders cleanly with both discord.botToken and env.DISCORD_BOT_TOKEN set, no duplicate.
Trade-off: when the user picks the explicit-env path, the token gets inlined into the Deployment spec (visible via kubectl get deploy -o yaml) instead of staying inside a Secret. Slightly less secure, but the user opted in by explicitly setting env.<KEY>.
A cleaner alternative (bigger schema change)
Add a agents.<name>.subprocessEnv map that gets passed through OpenAB's [agent].env config (so the subprocess sees it) without touching the container env. Then agents.<name>.env stays the place for container-level overrides, and the two never collide. This avoids the inline-token security trade-off but requires changes to both chart and OpenAB router config schema. This would also subsume the inherit_env feature request in #699 (CLOSED).
Related
Offer
Happy to send a PR for the minimal fix above. If the cleaner subprocessEnv direction is preferred I can sketch that too — needs guidance on the router-side schema.
Summary
When a user sets BOTH
agents.<name>.discord.botToken(or.slack.botToken/.slack.appToken/.stt.apiKey/.gateway.token) AND the same key inagents.<name>.env.*, the rendered Deployment ends up with duplicateenventries for the same key. Kubernetes rejects the apply:Chart
0.8.2, k8s 1.32 (OrbStack), helm 3.18.x.Why users hit this
Per the existing workaround for agent-subprocess env isolation (see related #699), users have to re-declare bot tokens in
agents.<name>.env.*so the subprocess can read them. But they also need to keepdiscord.botToken/slack.botTokenset so the chart's other paths (secret.yaml, etc.) work. Both paths feed the Deployment'senv:array, creating duplicates.Concrete
helm-install.shpattern that triggers the bug:The chart's
templates/deployment.yamllines 44-65 auto-promote.discord.botToken/.slack.botToken/.slack.appToken/.stt.apiKey/.gateway.tokeninto container env viavalueFrom.secretKeyRef. Lines 82-85 then loop$cfg.envand emit each key as inlinevalue:. Same key, two entries.Repro
values:
Run
helm upgrade --install ...→ apply fails with duplicate-key.Proposed fix (chart-side, minimal)
In
templates/deployment.yaml, guard each auto-promotion block with ahasKeycheck againstagents.<name>.env. When the user explicitly sets the env var, skip the secretKeyRef auto-promotion (the explicit value wins).Diff:
Verified locally against chart
0.8.2— patcheddeployment.yamlrenders cleanly with bothdiscord.botTokenandenv.DISCORD_BOT_TOKENset, no duplicate.Trade-off: when the user picks the explicit-env path, the token gets inlined into the Deployment spec (visible via
kubectl get deploy -o yaml) instead of staying inside a Secret. Slightly less secure, but the user opted in by explicitly settingenv.<KEY>.A cleaner alternative (bigger schema change)
Add a
agents.<name>.subprocessEnvmap that gets passed through OpenAB's[agent].envconfig (so the subprocess sees it) without touching the container env. Thenagents.<name>.envstays the place for container-level overrides, and the two never collide. This avoids the inline-token security trade-off but requires changes to both chart and OpenAB router config schema. This would also subsume theinherit_envfeature request in #699 (CLOSED).Related
[agent].inherit_envfeature request. The chart bug here is what makes the documented workaround (re-declaring tokens in[agent].env) actually unusable.0.8.2chart env-injection gap (gateway/LINE). Same generation of chart issues.Offer
Happy to send a PR for the minimal fix above. If the cleaner
subprocessEnvdirection is preferred I can sketch that too — needs guidance on the router-side schema.