YunaiV/ruoyi-vue-pro · error · NullPointerException
TenantContextHolder 不存在租户编号!可参考文档:{}
Error message
TenantContextHolder 不存在租户编号!可参考文档:{} What it means
yudao's TenantContextHolder stores the current tenant id in a ThreadLocal. getRequiredTenantId() throws NullPointerException when no tenant is set (e.g. a background job, async thread, or a request that skipped the tenant filter). It is a hard guard: code that needs a tenant must not run without one.
Source
Thrown at yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java:40
/**
* 获得租户编号
*
* @return 租户编号
*/
public static Long getTenantId() {
return TENANT_ID.get();
}
/**
* 获得租户编号。如果不存在,则抛出 NullPointerException 异常
*
* @return 租户编号
*/
public static Long getRequiredTenantId() {
Long tenantId = getTenantId();
if (tenantId == null) {
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
+ DocumentEnum.TENANT.getUrl());
}
return tenantId;
}
public static void setTenantId(Long tenantId) {
TENANT_ID.set(tenantId);
}
public static void setIgnore(Boolean ignore) {
IGNORE.set(ignore);
}
/**
* 当前是否忽略租户
*
* @return 是否忽略
*/View on GitHub (pinned to 0418084e22)
Solutions
- Propagate the tenant into async/scheduled threads (use yudao's tenant-aware task decorator or set TenantContextHolder.setTenantId(...) explicitly).
- Verify the endpoint is not excluded from the tenant filter; remove it from ignore lists if it requires a tenant.
- If the code legitimately has no tenant (cross-tenant/system task), use TenantUtils.executeIgnore(...) or getTenantId() (nullable) instead of getRequiredTenantId().
Example fix
// before: background job with no tenant context Long tenantId = TenantContextHolder.getRequiredTenantId(); // after: run the job under an explicit/ignored tenant context TenantUtils.execute(tenantId, () -> doWork()); // or, if system-level: TenantUtils.executeIgnore(() -> doWork());
Defensive patterns
Strategy: validation
Validate before calling
Long tid = TenantContextHolder.getTenantId();
if (tid == null) throw new IllegalStateException("No tenant in context; propagate via TenantUtils.execute(tenantId, ...)"); Type guard
static boolean hasTenant() { return TenantContextHolder.getTenantId() != null; } Try / catch
try { TenantContextHolder.getRequiredTenantId(); }
catch (NullPointerException e) { /* run under TenantUtils.executeIgnore or set explicit tenant */ } Prevention
- Propagate tenant context into async/scheduled threads
- Use TenantUtils.execute(...) for tenant-required work in background jobs
- Audit web-filter ignore lists against tenant-required endpoints
When it happens
Trigger: Calling getRequiredTenantId() from a @Async method, scheduled task, message listener, or new thread that did not inherit the tenant context; a request to a path excluded from TenantContextWebFilter; tenant filter ran but set no default tenant.
Common situations: Async/scheduled jobs that forget to propagate tenant; web-filter ignore-rules for a tenant-required endpoint; misconfigured TenantContextHolder default.
Related errors
AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14).
Data as JSON: /api/errors/d2b7637726f39b4c.
Report an issue: GitHub.