JuliusBrussee/caveman · error · Error

optional profile credentials cannot be array elements

Error message

optional profile credentials cannot be array elements

What it means

When rendering profile credential templates, renderDeep walks the config value recursively. Inside objects, a key whose template renders to undefined (optional credential absent) is simply omitted from the output; but inside arrays there is no way to omit an element, so an array item that renders to undefined would silently become a hole. The library throws instead of producing a corrupted array.

Source

Thrown at packages/cli/src/index.ts:5806

// renderDeep applies renderTemplate to every string leaf of a JSON value — used to
// render an agent's inline-config template before it is stringified into an env var.
// Optional credential references disappear as whole object properties when their
// source variable is unavailable. Secrets never enter generated JSON: the retained
// value is the agent-native `$OPENAI_API_KEY` reference, not its expansion.
function renderDeep(v: unknown, gw = gatewayURL(), env: NodeJS.ProcessEnv = process.env, options: RenderDeepOptions = {}): unknown {
  if (v === OPTIONAL_OPENAI_KEY_ENV_TEMPLATE) {
    const key = env.OPENAI_API_KEY;
    const inherited = typeof key === "string" && !!key.trim() && !/[\r\n]/.test(key);
    return (options.optionalOpenAIKeyEnvAvailable ?? inherited)
      ? options.optionalOpenAIKeyReference ?? "$OPENAI_API_KEY"
      : undefined;
  }
  if (typeof v === "string") return renderTemplate(v, gw);
  if (Array.isArray(v)) {
    return v.map((item) => {
      const rendered = renderDeep(item, gw, env, options);
      if (rendered === undefined) throw new Error("optional profile credentials cannot be array elements");
      return rendered;
    });
  }
  if (v && typeof v === "object") {
    const out: Record<string, unknown> = {};
    for (const [k, val] of Object.entries(v as Record<string, unknown>)) {
      const rendered = renderDeep(val, gw, env, options);
      if (rendered !== undefined) out[k] = rendered;
    }
    return out;
  }
  return v;
}

function stripJson5Comments(s: string): string {
  let out = "";
  let inString = false;
  let escaped = false;

View on GitHub (pinned to 5184b3d11a)

Solutions

  1. Move the optional credential reference out of the array and into an object position where an undefined render can be omitted.
  2. Provide the missing credential so the template renders to a defined value (set the env var / profile credential).
  3. Replace the array element with a concrete default value (e.g. empty string) instead of an optional template.
  4. Restructure the config so conditional values are handled by objects/conditional keys rather than array membership.

Example fix

// before
"args": ["--token", "${OPTIONAL_API_TOKEN}"]  // OPTIONAL_API_TOKEN unset -> throws

// after
"args": ["--token", "${OPTIONAL_API_TOKEN:-}"]  // or supply the credential, or drop the element
Defensive patterns

Strategy: validation

Validate before calling

function hasUndefinedRenderingArrayItems(value, gw, env, options) {
  if (Array.isArray(value)) {
    return value.some((item) => renderDeep(item, gw, env, options) === undefined);
  }
  return false;
}
// call before applying the profile config
if (hasUndefinedRenderingArrayItems(profileValue, gw, env, options)) {
  throw new Error('profile array element references a missing optional credential');
}

Type guard

function isRenderableArray(v, gw, env, options): v is unknown[] {
  return Array.isArray(v) && v.every((item) => renderDeep(item, gw, env, options) !== undefined);
}

Try / catch

try {
  renderConfig(profile, gw, env, options);
} catch (err) {
  if (err.message.includes('optional profile credentials cannot be array elements')) {
    console.error('Move optional credential references out of arrays or supply them.');
    process.exitCode = 1;
  } else throw err;
}

Prevention

When it happens

Trigger: Calling renderDeep (via profile/env template rendering) on a config value that is an array whose element is a template string or nested value that resolves to undefined — e.g. an array element referencing an optional credential like "${GW_API_KEY}" when that credential is not set, or an element that is itself an object whose required rendering yields undefined.

Common situations: A user puts an optional credential reference inside a JSON array in a profile config (e.g. env value arrays or command argument arrays) and the referenced optional secret is missing in the current environment; the config worked before because the key was at object level where omission is allowed.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-09-06). Data as JSON: /api/errors/f04107df767e6eac. Report an issue: GitHub.