{"record":{"id":"e556c09a70c96abe","repo":"langgenius/dify","slug":"bad-yaml-format","errorCode":null,"errorMessage":"bad YAML format","messagePattern":"bad YAML format","errorType":"exception","errorClass":"BadYamlFormatError","httpStatus":null,"severity":"error","filePath":"cli/src/store/store.ts","lineNumber":268,"sourceCode":"      const next = current[part]\n      if (next === null || next === undefined || typeof next !== 'object') return\n      current = next as Record<string, unknown>\n    }\n    if (!(lastKey in current)) return\n    delete current[lastKey]\n    this.setRawContent(dump(data, { lineWidth: -1, noRefs: true }))\n  }\n}\n\nfunction loadYaml(raw: string | undefined, file_path: string): Record<string, unknown> | null {\n  if (raw === undefined) return null\n  try {\n    const documents = loadAll(raw, { schema: YAML_LOAD_SCHEMA })\n    if (documents.length > 1)\n      throw new YAMLException('expected a single document in the stream, but found more')\n    return (documents[0] ?? {}) as Record<string, unknown>\n  } catch (err) {\n    if (err instanceof YAMLException) throw new BadYamlFormatError(file_path, raw, err)\n    throw err\n  }\n}\n\n/**\n * OS-keyring-based storage primitive. Sits at the same layer as\n * `FileBasedStore`: implements `Store` with each `Key<T>` corresponding to a\n * single keyring entry under the configured service. Values are JSON-encoded.\n */\nexport class KeyringBasedStore implements Store {\n  private readonly service: string\n\n  constructor(service: string) {\n    this.service = service\n  }\n\n  async get<T>(key: Key<T>): Promise<T> {\n    try {","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/cli/src/store/store.ts#L250-L286","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the error: it names the file, the reason, line/column, and shows a snippet with a `^` marker.","Open the file at the indicated line and fix the indentation/syntax; use spaces, never tabs.","Resolve any merge-conflict markers; ensure a single YAML document (no `---` separators).","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).","Validate with a linter (`yamllint <path>`) before re-running."],"exampleFix":"# before — tabs / bad indent in hosts.yml\ndefault:\n\thost: https://cloud.dify.ai   # tab — YAML rejects tabs\n  email: a@b.com               # inconsistent indent\n\n# after — spaces, consistent indent\ndefault:\n  host: https://cloud.dify.ai\n  email: a@b.com\n\n# nuclear option — reset and re-login\nmv ~/.config/difyctl/hosts.yml ~/.config/difyctl/hosts.yml.bak\ndifyctl auth login","handlingStrategy":"try-catch","validationCode":"// validate the YAML file is parseable and single-document before difyctl touches it\nimport { loadAll } from 'js-yaml'\nimport { readFileSync } from 'node:fs'\n\nfunction validateStoreYaml(path: string): void {\n  const docs = loadAll(readFileSync(path, 'utf8'))\n  if (docs.length > 1) throw new Error(`${path} must contain a single YAML document`)\n}","typeGuard":null,"tryCatchPattern":"import { BadYamlFormatError } from '@/store/errors'\n\ntry {\n  await store.getTyped<Registry>()\n} catch (err) {\n  if (err instanceof BadYamlFormatError) {\n    // err.message has file path + line/column + snippet\n    console.error(`store corrupt: ${err.message}`)\n    // recovery: back up and reset\n    throw err\n  }\n  throw err\n}","preventionTips":["Never hand-edit hosts.yml with tabs; use spaces and a YAML-aware editor.","Run `yamllint` after manual edits.","Avoid multi-document YAML (`---` separators) — the store rejects it.","Back up the file before resetting; removing it loses auth state."],"tags":["store","yaml","parsing","filesystem","config"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}