flipped-aurora/gin-vue-admin · error

httpHeader 必须是 {"Key":"Value"} 形式的 JSON 对象

Error message

httpHeader 必须是 {"Key":"Value"} 形式的 JSON 对象

What it means

validateTask throws "httpHeader 必须是 {\"Key\":\"Value\"} 形式的 JSON 对象" when a non-empty HttpHeader byte slice cannot be unmarshalled into map[string]string. Headers must be a flat JSON object of string keys to string values.

Source

Thrown at server/service/system/sys_timed_task.go:68

		return err
	}
	switch t.ExecutorType {
	case system.TimedTaskExecutorMethod:
		if _, ok := task.Get(t.MethodName); !ok {
			return fmt.Errorf("方法 %s 未注册", t.MethodName)
		}
		if len(t.Params) > 0 && !json.Valid(t.Params) {
			return errors.New("params 必须是合法 JSON")
		}
	case system.TimedTaskExecutorHTTP:
		u, err := url.Parse(t.HttpUrl)
		if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
			return errors.New("httpUrl 必须是合法的 http/https 地址")
		}
		if len(t.HttpHeader) > 0 {
			var hdr map[string]string
			if err := json.Unmarshal(t.HttpHeader, &hdr); err != nil {
				return errors.New(`httpHeader 必须是 {"Key":"Value"} 形式的 JSON 对象`)
			}
		}
	default:
		return fmt.Errorf("executorType 必须为 %s 或 %s", system.TimedTaskExecutorMethod, system.TimedTaskExecutorHTTP)
	}
	return nil
}

// checkNameUnique 软删除下不建 DB 唯一索引, 由服务层保证活跃行内唯一
func (s *TimedTaskService) checkNameUnique(ctx context.Context, name string, excludeID uint) error {
	var count int64
	db := global.GVA_DB.WithContext(ctx).Model(&system.SysTimedTask{}).Where("name = ?", name)
	if excludeID > 0 {
		db = db.Where("id <> ?", excludeID)
	}
	if err := db.Count(&count).Error; err != nil {
		return err
	}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Send HttpHeader as a flat JSON object with string values, e.g. {"Authorization":"Bearer x"}.
  2. Convert array-style header lists to an object before calling the API.
  3. Coerce numeric/boolean header values to strings client-side.
  4. Omit HttpHeader entirely when no custom headers are needed.

Example fix

// before
HttpHeader: []byte(`[{"key":"Authorization","value":"Bearer x"}]`)

// after
HttpHeader: []byte(`{"Authorization":"Bearer x"}`)
Defensive patterns

Strategy: validation

Validate before calling

if len(task.HttpHeader) > 0 {
    var hdr map[string]string
    if err := json.Unmarshal(task.HttpHeader, &hdr); err != nil {
        return errors.New("httpHeader must be a flat JSON object of string->string")
    }
}

Type guard

func validHTTPHeader(p []byte) bool {
    var hdr map[string]string
    return len(p) == 0 || json.Unmarshal(p, &hdr) == nil
}

Try / catch

if err := svc.UpdateTimedTask(ctx, task); err != nil {
    if strings.Contains(err.Error(), "httpHeader 必须") {
        http.Error(w, `httpHeader must be {"Key":"Value"} JSON`, http.StatusBadRequest)
        return
    }
    http.Error(w, err.Error(), http.StatusInternalServerError)
}

Prevention

When it happens

Trigger: Setting HttpHeader to a JSON array, a nested object ({"a":{"b":1}}), non-string values ({"count":1}), or invalid JSON; client sending headers as an array of {key,value} pairs.

Common situations: Copying curl -H style headers verbatim; frontends representing headers as arrays; numeric or boolean header values that Go's map[string]string cannot unmarshal.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/9f7f46b1889d902d. Report an issue: GitHub.