hashicorp/vault · error · Error

Vault expects data to be formatted as an JSON object.

Error message

Vault expects data to be formatted as an JSON object.

What it means

Thrown by the KV secret editing utility (ui/app/lib/kv-object.js:13). fromJSON() converts a KV secret's data payload into an array of {name, value} row objects for the editor UI. Vault KV secrets must be a JSON object (a map of string keys to values); if the supplied json is an array, string, number, or other non-object type, the guard throws before mapping.

Source

Thrown at ui/app/lib/kv-object.js:13

/**
 * Copyright IBM Corp. 2016, 2025
 * SPDX-License-Identifier: BUSL-1.1
 */

import ArrayProxy from '@ember/array/proxy';
import { typeOf } from '@ember/utils';
import { guidFor } from '@ember/object/internals';

export default ArrayProxy.extend({
  fromJSON(json) {
    if (json && typeOf(json) !== 'object') {
      throw new Error('Vault expects data to be formatted as an JSON object.');
    }
    const contents = Object.keys(json || []).map((key) => {
      const obj = {
        name: key,
        value: json[key],
      };
      guidFor(obj);
      return obj;
    });
    this.setObjects(
      contents.sort((a, b) => {
        if (a.name === '') {
          return 1;
        }
        if (b.name === '') {
          return -1;
        }
        return a.name.localeCompare(b.name);

View on GitHub (pinned to 744b611b57)

Solutions

  1. Rewrite the secret so its data is a JSON object of key/value pairs (vault kv put secret/foo mykey=myvalue)
  2. If a list is genuinely needed, store it as the value of a key (e.g. {"items": "a,b,c"} or a JSON-stringified array)

Example fix

// before: top-level array breaks the editor
await fetch('/v1/secret/data/app', { method: 'POST', body: JSON.stringify({ data: ['a', 'b'] }) });

// after: data must be a key/value object
await fetch('/v1/secret/data/app', { method: 'POST', body: JSON.stringify({ data: { items: 'a,b' } }) });
Defensive patterns

Strategy: type-guard

Type guard

import { typeOf } from '@ember/utils';
// Mirrors the library's own check: typeOf returns 'object' only for plain objects,
// 'array' for arrays, 'string'/'number'/etc. otherwise
function isKvDataObject(json: unknown): json is Record<string, unknown> {
  return !!json && typeOf(json) === 'object';
}

if (!isKvDataObject(secretData)) {
  throw new Error('KV secret data must be a JSON object of key/value pairs');
}

Try / catch

try {
  kvObject.fromJSON(data);
} catch (e) {
  if (e.message.includes('formatted as an JSON object')) {
    notifyUser('This secret is not a key/value object — rewrite it as {"key": "value"} via the API/CLI');
    renderRawJsonView(data);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Loading or rendering a KV secret (v1 or v2) whose data field is not a plain object — e.g. written via the raw HTTP API as a top-level JSON array or scalar — or calling KvObject.fromJSON directly with such a payload.

Common situations: Secrets written by scripts or API integrations that serialize a list or bare value instead of a key/value map; migrating tools that emit JSON arrays; malformed JSON produced upstream that parses to a non-object.

Related errors


AI-assisted analysis of hashicorp/vault@744b611b57 (2026-08-15). Data as JSON: /api/errors/89994b4f53d835e1. Report an issue: GitHub.