{"record":{"id":"a5ac7db664adb3f0","repo":"FiloSottile/age","slug":"invalid-stanza-type-q","errorCode":null,"errorMessage":"invalid stanza type: %q","messagePattern":"invalid stanza type: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/format/format.go","lineNumber":113,"sourceCode":"\treturn total, nil\n}\n\n// LastLineIsEmpty returns whether the last output line was empty, either\n// because no input was written, or because a multiple of BytesPerLine was.\n//\n// Calling LastLineIsEmpty before Close is meaningless.\nfunc (w *WrappedBase64Encoder) LastLineIsEmpty() bool {\n\treturn w.written%ColumnsPerLine == 0\n}\n\nconst intro = \"age-encryption.org/v1\\n\"\n\nvar stanzaPrefix = []byte(\"->\")\nvar footerPrefix = []byte(\"---\")\n\nfunc (r *Stanza) Marshal(w io.Writer) error {\n\tif !isValidString(r.Type) {\n\t\treturn fmt.Errorf(\"invalid stanza type: %q\", r.Type)\n\t}\n\tfor _, a := range r.Args {\n\t\tif !isValidString(a) {\n\t\t\treturn fmt.Errorf(\"invalid stanza argument: %q\", a)\n\t\t}\n\t}\n\tif _, err := w.Write(stanzaPrefix); err != nil {\n\t\treturn err\n\t}\n\tif _, err := io.WriteString(w, \" \"+r.Type); err != nil {\n\t\treturn err\n\t}\n\tfor _, a := range r.Args {\n\t\tif _, err := io.WriteString(w, \" \"+a); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif _, err := io.WriteString(w, \"\\n\"); err != nil {","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/internal/format/format.go#L95-L131","documentation":"format.Stanza.Marshal validates that the stanza Type is a 'valid string' (single line, printable ASCII, no spaces/newlines per isValidString) before writing. A Type containing newlines, spaces, or non-ASCII/control bytes would corrupt the age v1 wire format, so Marshal refuses it.","triggerScenarios":"Constructing a &format.Stanza{Type: ...} programmatically (e.g. in a plugin or IdentityV1 implementation) with a Type containing a space, '\\n', or non-printable/non-ASCII character, then calling Marshal.","commonSituations":"Custom age plugin stanzas whose type comes from unvalidated user input or config; strings read from files that keep a trailing newline.","solutions":["Sanitize the Type: trim whitespace/newlines and ensure printable-ASCII, no spaces","Use strings.TrimSpace and reject values with invalid bytes before building the Stanza","Log the offending %q value; it names the exact invalid Type"],"exampleFix":"// before\nst := &format.Stanza{Type: userProvidedType}\nst.Marshal(w)\n// after\ntype1 := strings.TrimSpace(userProvidedType)\nif !isValidType(type1) { return fmt.Errorf(\"bad stanza type %q\", type1) }\nst := &format.Stanza{Type: type1}\nst.Marshal(w)","handlingStrategy":"validation","validationCode":"func validStanzaString(s string) bool {\n    if s == \"\" { return false }\n    for _, c := range s {\n        if c <= 32 || c > 126 { return false }\n    }\n    return true\n}\nif !validStanzaString(stanzaType) { return errors.New(\"stanza type must be printable ASCII, no spaces\") }","typeGuard":"func isPlainASCIIWord(s string) bool {\n    return s != \"\" && strings.IndexFunc(s, func(r rune) bool { return r <= 32 || r > 126 }) < 0\n}","tryCatchPattern":null,"preventionTips":["TrimSpace all externally sourced stanza fields","Base64-encode anything that may contain spaces/newlines/binary","Write a unit test marshalling every stanza your plugin emits"],"tags":["age","format","stanza","serialization"],"backgroundTag":"invalid-stanza-type","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}