{"record":{"id":"1e7c5bbcd5f2e752","repo":"sipeed/picoclaw","slug":"deltachat-invalid-chatmail-server-marker-q-use","errorCode":null,"errorMessage":"deltachat: invalid chatmail server marker %q; use settings.email like %q","messagePattern":"deltachat: invalid chatmail server marker %q; use settings\\.email like %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/deltachat/deltachat.go","lineNumber":178,"sourceCode":"func parseDeltaChatEmailSetting(value string) (string, bool, error) {\n\temail := strings.TrimSpace(value)\n\tif email == \"\" {\n\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\"deltachat: email is required.\\nNext step: choose one of the chatmail servers below and set channel_list.deltachat.settings.email to %q, or use the same @server form with another chatmail relay. Run `picoclaw g` again; PicoClaw will create the account, print the generated full email address, and stop so you can save that address in the config.\\nAvailable chatmail servers:\\n%s\",\n\t\t\t\"@\"+defaultChatmailRelays[0].Domain,\n\t\t\tformatChatmailRelayList(),\n\t\t)\n\t}\n\tif !strings.HasPrefix(email, \"@\") {\n\t\treturn email, false, nil\n\t}\n\tdomain := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(email, \"@\")))\n\tif domain == \"\" {\n\t\treturn \"\", false, fmt.Errorf(\"deltachat: email %q is missing a chatmail server. Use %q or one of:\\n%s\",\n\t\t\temail, \"@\"+defaultChatmailRelays[0].Domain, formatChatmailRelayList())\n\t}\n\tif strings.Contains(domain, \"@\") || strings.ContainsAny(domain, \"/\\\\ \\t\\r\\n\") {\n\t\treturn \"\", false, fmt.Errorf(\"deltachat: invalid chatmail server marker %q; use settings.email like %q\",\n\t\t\temail, \"@\"+defaultChatmailRelays[0].Domain)\n\t}\n\treturn domain, true, nil\n}\n\nfunc formatChatmailRelayList() string {\n\tvar b strings.Builder\n\tfor _, relay := range defaultChatmailRelays {\n\t\tfmt.Fprintf(&b, \"  @%-34s %s\\n\", relay.Domain, relay.Location)\n\t}\n\treturn strings.TrimRight(b.String(), \"\\n\")\n}\n\nfunc buildChatmailAccountQR(domain string) string {\n\treturn fmt.Sprintf(\"DCACCOUNT:https://%s/new\", domain)\n}\n\n// NewDeltaChatChannel validates config and resolves the RPC server + data dir.","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/deltachat/deltachat.go#L160-L196","documentation":"The `@server` marker contains characters that can never be a domain: a second `@`, or any slash, backslash, space, tab, CR, or LF. parseDeltaChatEmailSetting rejects these to prevent injecting malformed values into the DCACCOUNT QR URL built as `DCACCOUNT:https://<domain>/new` and into shell/terminal output.","triggerScenarios":"settings.email values like `@a@b`, `@server path`, `@server/path`, `@server\\path`, or a multi-line YAML block scalar leaking a newline into the value.","commonSituations":"YAML folded scalars or quoted strings containing spaces; paste of a full email into the @-marker slot (user@host becomes @user@host after edits); config values copied from prose that includes a trailing comment or space.","solutions":["Set email to exactly `@domain.tld` with no spaces, slashes, or extra @ — e.g. `@nine.testrun.org`.","If you meant a full address, drop the leading @ and use `user@server` directly (that form is accepted and returns early).","Check the YAML quoting: use a plain double-quoted single-line scalar for email.","If templating, strip whitespace/newlines from the substituted server variable."],"exampleFix":"# before\nsettings:\n  email: \"@nine.testrun.org extra\"   # or \"@user@nine.testrun.org\"\n\n# after\nsettings:\n  email: \"@nine.testrun.org\"","handlingStrategy":"validation","validationCode":"func validChatmailMarker(v string) bool {\n    if !strings.HasPrefix(v, \"@\") { return true }\n    d := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(v, \"@\")))\n    return d != \"\" && !strings.Contains(d, \"@\") && !strings.ContainsAny(d, \"/\\\\ \\t\\r\\n\")\n}","typeGuard":"func validChatmailMarker(v string) bool {\n    if !strings.HasPrefix(v, \"@\") { return true }\n    d := strings.TrimPrefix(v, \"@\")\n    return !strings.ContainsAny(d, \"@/\\\\ \\t\\r\\n\")\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"invalid chatmail server marker\") {\n    return errors.New(\"email @marker must be exactly one domain: @nine.testrun.org\")\n}","preventionTips":["Keep email on one YAML line, double-quoted.","Never paste a full address after an @; the full-address form needs no leading @.","Strip whitespace in config templating before substitution."],"tags":["deltachat","go","config","validation","injection-guard"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}