tinyhumansai/openhuman · error · Error

"{key}" is required

Error message

"{key}" is required

What it means

Reconfigure validation in InstalledServerDetail: before calling mcpClientsApi.updateEnv, every key in visibleEnvKeys must have a non-empty trimmed value in reconfigValues. The check is strict because update_env has replace-all semantics (DELETEs all env rows then INSERTs the submitted set) - a blank value would silently strip required env on the next reconnect. Throws the localized 'mcp.install.missingRequired' with {key} substituted.

Source

Thrown at app/src/components/channels/mcp/InstalledServerDetail.tsx:199

  // sets may be partial; the form requires every key so a reconnect never drops
  // a required var (issue #3039 gap B6 — suggested values were never persisted).
  const handleApplySuggestedEnv = useCallback(
    (env: Record<string, string>) => {
      log('suggested_env received, opening reconfigure form keys=%o', Object.keys(env));
      setShowAssistant(false);
      openReconfigure(env);
    },
    [openReconfigure]
  );

  const handleSaveReconfigure = useCallback(() => {
    void runBusy(async () => {
      // Replace-all semantics (update_env DELETEs then INSERTs): every key must
      // have a value or the server loses required env on reconnect. Mirror the
      // install dialog's validation.
      for (const key of visibleEnvKeys) {
        if (!reconfigValues[key]?.trim()) {
          throw new Error(t('mcp.install.missingRequired').replace('{key}', key));
        }
      }
      log('reconfigure save server_id=%s', server.server_id);
      const result = await mcpClientsApi.updateEnv({
        server_id: server.server_id,
        env: reconfigValues,
      });
      setTools(result.tools ?? []);
      if (result.status === 'unauthorized') {
        // A 401 after reconfigure: show the actionable auth reason (use Sign in
        // / token rejected / credential required) the same way the Connect
        // dialog does — the raw 401 message is withheld server-side (#4289).
        const key = authHintMessageKey(result.auth_hint);
        throw new Error(key ? t(key) : t('mcp.detail.reconfigureReconnectFailed'));
      }
      if (result.status !== 'connected') {
        throw new Error(result.error ?? t('mcp.detail.reconfigureReconnectFailed'));
      }

View on GitHub (pinned to 7491200858)

Solutions

  1. Enter a value for the exact key named in the message, then Save again
  2. If the var is genuinely optional, remove it from the server's env keys so it is not part of the replace-all set, rather than submitting it blank
  3. Copy the full original value from the server's configuration before reconfiguring

Example fix

// before - throws only inside the busy handler after Save is clicked
for (const key of visibleEnvKeys) {
  if (!reconfigValues[key]?.trim()) {
    throw new Error(t('mcp.install.missingRequired').replace('{key}', key));
  }
}

// after - also disable Save up front so the error cannot happen
const reconfigInvalid = visibleEnvKeys.some(k => !reconfigValues[k]?.trim());
// <Button disabled={reconfigInvalid || busy}>Save</Button>
Defensive patterns

Strategy: validation

Validate before calling

// Run the identical check before opening the busy path
const invalidKeys = visibleEnvKeys.filter(k => !reconfigValues[k]?.trim());
const canSave = invalidKeys.length === 0;
// <Button disabled={!canSave || busy} onClick={handleSaveReconfigure}>Save</Button>

Prevention

When it happens

Trigger: Saving the Reconfigure dialog with any visible env field left empty or whitespace-only - e.g. the user clears a value intending to 'keep it as-is', or a prefill did not populate one key.

Common situations: Users assume blank means 'unchanged' (it means 'delete this var' server-side, hence the guard); migrating a server whose stored env keys have no values; copying a .env block where one line lost its value.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/29509e39b44be128. Report an issue: GitHub.