YunaiV/yudao-cloud · error · IllegalArgumentException

未知联系状态:{}

Error message

未知联系状态:{}

What it means

CrmCustomerMapper.selectPage throws IllegalArgumentException when the backlog contactStatus filter is not one of the three supported constants: CONTACT_TODAY (今天需联系), CONTACT_EXPIRED (已逾期), CONTACT_ALREADY (已联系). The value is compared literally, so any other integer (or a wrong-cased/mispacked value) reaches the else branch. Note the method also asserts pool must be null when contactStatus is set.

Source

Thrown at yudao-module-crm/yudao-module-crm-server/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java:81

                .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
                .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
                .eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel())
                .eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource())
                .eqIfPresent(CrmCustomerDO::getFollowUpStatus, pageReqVO.getFollowUpStatus());

        // backlog 查询
        if (ObjUtil.isNotNull(pageReqVO.getContactStatus())) {
            Assert.isNull(pageReqVO.getPool(), "pool 必须是 null");
            LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
            LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
            if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_TODAY)) { // 今天需联系
                query.between(CrmCustomerDO::getContactNextTime, beginOfToday, endOfToday);
            } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_EXPIRED)) { // 已逾期
                query.lt(CrmCustomerDO::getContactNextTime, beginOfToday);
            } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_ALREADY)) { // 已联系
                query.between(CrmCustomerDO::getContactLastTime, beginOfToday, endOfToday);
            } else {
                throw new IllegalArgumentException("未知联系状态:" + pageReqVO.getContactStatus());
            }
        }
        return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
    }

    default CrmCustomerDO selectByCustomerName(String name) {
        return selectOne(CrmCustomerDO::getName, name);
    }

    default PageResult<CrmCustomerDO> selectPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
                                                                      CrmCustomerPoolConfigDO poolConfig,
                                                                      Long ownerUserId) {
        final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, ownerUserId);
        return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class));
    }

    default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO,
                                                  CrmCustomerPoolConfigDO poolConfig,

View on GitHub (pinned to 477be9dd49)

Solutions

  1. Pass only contactStatus values defined in CrmCustomerPageReqVO: CONTACT_TODAY, CONTACT_EXPIRED, CONTACT_ALREADY
  2. Do not combine pool with contactStatus in the same request (pool must be null)
  3. Sync the frontend filter options with the backend constants after upgrades

Example fix

// before
GET /admin-api/crm/customer/page?contactStatus=4&pool=false

// after
GET /admin-api/crm/customer/page?contactStatus=1  // 1 = CONTACT_TODAY, no pool param
Defensive patterns

Strategy: validation

Validate before calling

Integer s = pageReqVO.getContactStatus();
if (s != null && !(s.equals(CrmCustomerPageReqVO.CONTACT_TODAY)
        || s.equals(CrmCustomerPageReqVO.CONTACT_EXPIRED)
        || s.equals(CrmCustomerPageReqVO.CONTACT_ALREADY))) {
    throw new IllegalArgumentException("contactStatus 必须为 1/2/3");
}

Type guard

boolean isBacklogStatus(Integer s) {
    return s != null && Set.of(CrmCustomerPageReqVO.CONTACT_TODAY,
        CrmCustomerPageReqVO.CONTACT_EXPIRED,
        CrmCustomerPageReqVO.CONTACT_ALREADY).contains(s);
}

Prevention

When it happens

Trigger: GET /admin-api/crm/customer/page with contactStatus=4 or 0; a custom CRM frontend passing its own enum numbering; chaining pool + contactStatus parameters (pool must be null); client sending contactStatus as string '1' where a different constant set is expected.

Common situations: Frontend filter dropdown extended with new statuses without a backend update; API consumers guessing the enum values instead of reading CrmCustomerPageReqVO constants; stale frontend after backend constants changed.

Related errors


AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14). Data as JSON: /api/errors/2bdf3ef256f99f82. Report an issue: GitHub.