jeessy2/ddns-go · error

序列化请求体失败: %w

Error message

序列化请求体失败: %w

What it means

request() fails to json.Marshal the request body before sending it to the DNSMgr API. With the current callers the body is a map[string]interface{} of plain strings/ints, which is always marshalable in practice, so this error indicates a non-marshalable value reached request() (channels, funcs, invalid types) — typically after a code modification.

Source

Thrown at dns/hipmdnsmgr.go:196

// 参考 dnsmgr.ts 中的 request<T>() 方法
func (h *HiPMDnsMgr) request(baseURL, apiToken, method, path string, body interface{}) (*DnsMgrApiResponse, error) {
	// 参考 dnsmgr.ts 中的 URL 处理方式
	// Ensure baseUrl doesn't end with /api and path starts with /
	base := strings.TrimSuffix(baseURL, "/")
	base = strings.TrimSuffix(base, "/api")

	normalizedPath := path
	if !strings.HasPrefix(normalizedPath, "/") {
		normalizedPath = "/" + normalizedPath
	}

	url := base + "/api" + normalizedPath

	var bodyReader *bytes.Buffer
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			return nil, fmt.Errorf("序列化请求体失败: %w", err)
		}
		bodyReader = bytes.NewBuffer(jsonBody)
	} else {
		bodyReader = bytes.NewBuffer(nil)
	}

	req, err := http.NewRequest(method, url, bodyReader)
	if err != nil {
		return nil, err
	}

	// 设置请求头
	headers := h.getHeaders(apiToken)
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	resp, err := h.httpClient.Do(req)

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Inspect the wrapped %w cause — it names the unsupported json type
  2. Ensure every value in the request body map is a JSON-marshalable type (string, int, bool, slices, maps, tagged structs)
  3. Add json.Marshaler or proper struct tags for custom types
  4. If TTL came from config, confirm strconv.Atoi parsing didn't inject odd values (stock code defaults to 600 anyway)

Example fix

// before
body := map[string]interface{}{"callback": func(r *http.Request) {}} // unmarshalable
// after
body := map[string]interface{}{"name": name, "type": recordType, "value": value, "ttl": ttl, "line": "0"}
Defensive patterns

Strategy: validation

Validate before calling

// guard before passing a body to any low-level request
func ensureMarshalable(body interface{}) error {
    if body == nil {
        return nil
    }
    _, err := json.Marshal(body)
    return err // surfaces unmarshalable types before the HTTP call
}

Prevention

When it happens

Trigger: Calling createRecord/updateExistingRecord (via request) with a body containing a value that encoding/json cannot marshal: e.g. a channel, function, or cyclic/unsupported type placed into the body map.

Common situations: Developer adds a new field to the request body with a custom type lacking json marshaling, or passes a struct with unexported-only/unsupported fields; never occurs with stock string/int map bodies in normal operation.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/abffefc1ab6a2b6d. Report an issue: GitHub.