langgenius/dify · error · BadYamlFormatError

bad YAML format

Error message

bad YAML format

What it means

BadYamlFormatError (BaseError, ClientError → exit 1) thrown by loadYaml (store.ts:268) when js-yaml's loadAll throws a YAMLException OR when the input yields more than one YAML document (store.ts:264-265 explicitly rejects multi-doc streams). The wrapper enriches the error with the file path, the parser's reason, line/column, and an excerpt of the offending region (see excerpt() in store/errors.ts). loadYaml runs on every YamlStore read/write path (doGet/doSet/doUnset/getTyped/setTyped), so any corruption in hosts.yml or another store file surfaces here.

Source

Thrown at cli/src/store/store.ts:268

      const next = current[part]
      if (next === null || next === undefined || typeof next !== 'object') return
      current = next as Record<string, unknown>
    }
    if (!(lastKey in current)) return
    delete current[lastKey]
    this.setRawContent(dump(data, { lineWidth: -1, noRefs: true }))
  }
}

function loadYaml(raw: string | undefined, file_path: string): Record<string, unknown> | null {
  if (raw === undefined) return null
  try {
    const documents = loadAll(raw, { schema: YAML_LOAD_SCHEMA })
    if (documents.length > 1)
      throw new YAMLException('expected a single document in the stream, but found more')
    return (documents[0] ?? {}) as Record<string, unknown>
  } catch (err) {
    if (err instanceof YAMLException) throw new BadYamlFormatError(file_path, raw, err)
    throw err
  }
}

/**
 * OS-keyring-based storage primitive. Sits at the same layer as
 * `FileBasedStore`: implements `Store` with each `Key<T>` corresponding to a
 * single keyring entry under the configured service. Values are JSON-encoded.
 */
export class KeyringBasedStore implements Store {
  private readonly service: string

  constructor(service: string) {
    this.service = service
  }

  async get<T>(key: Key<T>): Promise<T> {
    try {

View on GitHub (pinned to ef8544b173)

Solutions

  1. Read the error: it names the file, the reason, line/column, and shows a snippet with a `^` marker.
  2. Open the file at the indicated line and fix the indentation/syntax; use spaces, never tabs.
  3. Resolve any merge-conflict markers; ensure a single YAML document (no `---` separators).
  4. If the file is unrecoverable, the hint suggests removing it to reset — back it up first, then `rm <path>`; difyctl will recreate it on next write (you will need to `difyctl auth login` again for hosts.yml).
  5. Validate with a linter (`yamllint <path>`) before re-running.

Example fix

# before — tabs / bad indent in hosts.yml
default:
	host: https://cloud.dify.ai   # tab — YAML rejects tabs
  email: a@b.com               # inconsistent indent

# after — spaces, consistent indent
default:
  host: https://cloud.dify.ai
  email: a@b.com

# nuclear option — reset and re-login
mv ~/.config/difyctl/hosts.yml ~/.config/difyctl/hosts.yml.bak
difyctl auth login
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the YAML file is parseable and single-document before difyctl touches it
import { loadAll } from 'js-yaml'
import { readFileSync } from 'node:fs'

function validateStoreYaml(path: string): void {
  const docs = loadAll(readFileSync(path, 'utf8'))
  if (docs.length > 1) throw new Error(`${path} must contain a single YAML document`)
}

Try / catch

import { BadYamlFormatError } from '@/store/errors'

try {
  await store.getTyped<Registry>()
} catch (err) {
  if (err instanceof BadYamlFormatError) {
    // err.message has file path + line/column + snippet
    console.error(`store corrupt: ${err.message}`)
    // recovery: back up and reset
    throw err
  }
  throw err
}

Prevention

When it happens

Trigger: Hand-editing hosts.yml and breaking indentation, using tabs, unbalanced quotes, or a stray `:`. Also: a multi-document file (--- separator) which the store rejects; a file written by a newer difyctl using tags the loaded schema rejects; merge keys (!) handled via CORE_SCHEMA.withTags — only binary/merge/omap/pairs/set/timestamp are allowed. Also accidental binary/JSON content saved as .yml.

Common situations: Manual edit of hosts.yml to fix something; merge conflict resolution that left conflict markers (<<<<<<<, =======, >>>>>>>) which YAML can't parse; an editor inserting tabs; sync tools (Dropbox, git) writing a partial file; downgrade after an upgrade changed the schema.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/e556c09a70c96abe. Report an issue: GitHub.