{"record":{"id":"0a80bf77aebf0ea3","repo":"multica-ai/multica","slug":"marshal-hermes-config-w","errorCode":null,"errorMessage":"marshal hermes config: %w","messagePattern":"marshal hermes config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_home.go","lineNumber":905,"sourceCode":"\t\tval,\n\t)\n}\n\n// yamlStringSeq builds a YAML sequence node of string scalars.\nfunc yamlStringSeq(vals []string) *yaml.Node {\n\tseq := &yaml.Node{Kind: yaml.SequenceNode, Tag: \"!!seq\"}\n\tfor _, v := range vals {\n\t\tseq.Content = append(seq.Content, &yaml.Node{Kind: yaml.ScalarNode, Tag: \"!!str\", Value: v})\n\t}\n\treturn seq\n}\n\n// marshalYAMLToFile renders a YAML node to dst as a 0600 file (it can hold\n// inline secrets) via atomic replace.\nfunc marshalYAMLToFile(doc *yaml.Node, dst string) error {\n\tout, err := yaml.Marshal(doc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal hermes config: %w\", err)\n\t}\n\treturn writeFileAtomic(dst, out, 0o600)\n}\n\n// writeFileAtomic writes data to a temp file in the destination directory with\n// the given perms, then renames it over dst — so readers never see a partial\n// file and a prior file's looser permissions are replaced.\nfunc writeFileAtomic(dst string, data []byte, perm os.FileMode) error {\n\tdir := filepath.Dir(dst)\n\ttmp, err := os.CreateTemp(dir, \".hermes-tmp-*\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create temp for %s: %w\", dst, err)\n\t}\n\ttmpName := tmp.Name()\n\tdefer os.Remove(tmpName) // no-op once renamed\n\tif _, err := tmp.Write(data); err != nil {\n\t\ttmp.Close()\n\t\treturn fmt.Errorf(\"write temp for %s: %w\", dst, err)","sourceCodeStart":887,"sourceCodeEnd":923,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_home.go#L887-L923","documentation":"marshalYAMLToFile failed to yaml.Marshal the in-memory config node tree. With a Node-based document this is rare: it indicates content the encoder cannot represent (invalid character data, incompatible tag/type on a node) rather than a filesystem problem — the write happens afterwards.","triggerScenarios":"A config.yaml that parsed into nodes the v3 encoder rejects on re-marshal — unusual anchors/aliases or tags produced by other YAML tooling, or corrupted scalar values with invalid UTF-8.","commonSituations":"Exotic hand-crafted YAML in ~/.hermes/config.yaml (custom local tags like !!python/object, binary scalars) written by Python tooling; extremely old or nonstandard YAML generators.","solutions":["Inspect config.yaml for custom tags (!!python/..., !binary), anchors/aliases, or non-UTF-8 bytes; simplify them.","Re-save the config with a standard YAML writer to normalize it.","Copy the user's essential settings (model, api_key) into a fresh minimal config.yaml and delete the exotic one.","If unfixable, note the code copies the config verbatim only on parse failure — a file that parses but cannot re-marshal must be simplified by hand."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := marshalYAMLToFile(&doc, dstConfig); err != nil {\n\tif strings.Contains(err.Error(), \"marshal hermes config\") {\n\t\t// encoder rejected exotic nodes: fall back to verbatim copy of the source\n\t\treturn writeFileAtomic(dstConfig, srcData, 0o600)\n\t}\n\treturn err\n}","preventionTips":["Avoid custom YAML tags and binary scalars in ~/.hermes/config.yaml.","Regenerate suspect configs with a standard YAML writer to normalize node shapes."],"tags":["yaml","config","encoding","hermes","execenv"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}