{"record":{"id":"004f51866ededd89","repo":"larksuite/cli","slug":"parse-policy-yaml-multiple-yaml-documents-are-not","errorCode":null,"errorMessage":"parse policy yaml: multiple YAML documents are not allowed","messagePattern":"parse policy yaml: multiple YAML documents are not allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmdpolicy/yaml/schema.go","lineNumber":114,"sourceCode":"//\n// Semantic validation (MaxRisk taxonomy, identity values, glob syntax) is\n// the caller's responsibility -- run each result through\n// internal/cmdpolicy.ValidateRule before handing it to the engine.\nfunc Parse(data []byte) ([]*platform.Rule, error) {\n\tvar s fileSchema\n\tdec := gopkgyaml.NewDecoder(bytesReader(data))\n\tdec.KnownFields(true)\n\tif err := dec.Decode(&s); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse policy yaml: %w\", err)\n\t}\n\n\t// Reject multi-document input: yaml.v3 only decodes one document\n\t// per call, so a stray \"---\" followed by another document would\n\t// silently drop the trailing rule.\n\tvar extra fileSchema\n\tif err := dec.Decode(&extra); !errors.Is(err, io.EOF) {\n\t\tif err == nil {\n\t\t\treturn nil, fmt.Errorf(\"parse policy yaml: multiple YAML documents are not allowed\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"parse policy yaml: %w\", err)\n\t}\n\n\tif s.Rules != nil {\n\t\tif len(*s.Rules) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"parse policy yaml: 'rules:' is present but empty; remove the key, or list at least one rule\")\n\t\t}\n\t\tif !s.ruleSchema.isZero() {\n\t\t\treturn nil, fmt.Errorf(\"parse policy yaml: top-level rule fields cannot be combined with a 'rules:' list; move every rule under 'rules:'\")\n\t\t}\n\t\tout := make([]*platform.Rule, 0, len(*s.Rules))\n\t\tfor _, rs := range *s.Rules {\n\t\t\tout = append(out, rs.toRule())\n\t\t}\n\t\treturn out, nil\n\t}\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/cmdpolicy/yaml/schema.go#L96-L132","documentation":"After decoding the first document, Parse requires a second Decode to return io.EOF. If a second document decodes successfully, the input contained multiple '---'-separated documents. Since yaml.v3 decodes only one document per call, a trailing document would be silently dropped, so Parse rejects multi-document input explicitly.","triggerScenarios":"Calling Parse on bytes containing two documents separated by '---', e.g. concatenated policy files or a heredoc with a stray '---' separator.","commonSituations":"Appending policy files with cat; Kubernetes-style multi-document manifests pasted into a policy file; templates emitting leading '---' plus inner separators.","solutions":["Remove the extra document and '---' separator so the file holds one document.","Merge multiple rule sets into a single 'rules:' list.","Split content into separate policy files and load each individually."],"exampleFix":"// before\nname: a\n---\nname: b\n// after\nrules:\n  - name: a\n  - name: b","handlingStrategy":"validation","validationCode":"if bytes.Count(data, []byte(\"\\n---\")) > 0 {\n\treturn fmt.Errorf(\"policy file must contain exactly one YAML document\")\n}","typeGuard":null,"tryCatchPattern":"rules, err := yaml.Parse(data)\nif err != nil && strings.Contains(err.Error(), \"multiple YAML documents\") {\n\treturn fmt.Errorf(\"split the file or merge into a single rules: list: %w\", err)\n}","preventionTips":["Never concatenate policy files with cat; merge rule lists instead.","Strip '---' front-matter separators before loading generated files.","Convert multi-document manifests into one document with a 'rules:' list.","Add a pre-commit check rejecting '---' in policy files."],"tags":["go","yaml","config","multi-document"],"backgroundTag":"yaml-multi-document","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}