dromara/Sa-Token · error · ApiKeyException

12304

12304

Error message

ApiKey 值不可为空

What it means

ApiKeyException with error code 12304 thrown by ApiKeyModel.checkByCanSaved() — the pre-persistence sanity check — when the apiKey field is empty (SaFoxUtil.isEmpty). checkByCanSaved is run before saving an ApiKeyModel to storage; the same method also enforces loginId, createTime, expiresTime and isValid, each failing with code 12304 but distinct messages.

Source

Thrown at sa-token-plugin/sa-token-apikey/src/main/java/cn/dev33/satoken/apikey/model/ApiKeyModel.java:143

		return this.extraData.get(key);
	}

	/**
	 * 删除扩展数据
	 */
	public Object removeExtra(String key) {
		if (this.extraData == null) {
			return null;
		}
		return this.extraData.remove(key);
	}

	/**
	 * 数据自检,判断是否可以保存入库
	 */
	public void checkByCanSaved() {
		if (SaFoxUtil.isEmpty(this.apiKey)) {
			throw new ApiKeyException("ApiKey 值不可为空").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
		}
		if (this.loginId == null) {
			throw new ApiKeyException("无效 ApiKey: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
		}
		if (this.createTime == 0) {
			throw new ApiKeyException("请指定 createTime 创建时间").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
		}
		if (this.expiresTime == 0) {
			throw new ApiKeyException("请指定 expiresTime 过期时间").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
		}
		if (this.isValid == null) {
			throw new ApiKeyException("请指定 isValid 是否生效").setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12304);
		}
	}

	/**
	 * 获取:此 ApiKey 的剩余有效期(秒), -1=永不过期
	 * @return /

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Generate a key before saving: use the plugin's key generator (e.g. SaFoxUtil / apiKeyManager random generator) or supply a non-empty unique value.
  2. If the key comes from user input, validate it is non-blank at the API boundary and return a 400 instead of letting persistence fail.
  3. For the sibling messages, also set loginId, createTime, expiresTime (non-zero) and isValid before save.
  4. Catch ApiKeyException and read getCode()==12304 to map to a client-facing validation error.

Example fix

// before
ApiKeyModel model = new ApiKeyModel();
model.setLoginId(10001);
model.setCreateTime(System.currentTimeMillis());
model.setExpiresTime(System.currentTimeMillis() + 86400000L);
model.setIsValid(true);
saApiKeyTemplate.save(model); // throws 12304: apiKey empty

// after
model.setApiKey(SaFoxUtil.getRandomString(32)); // or framework-generated key
saApiKeyTemplate.save(model);
Defensive patterns

Strategy: validation

Validate before calling

ApiKeyModel m = new ApiKeyModel();
m.setApiKey(generateKey());           // non-empty
m.setLoginId(loginId);                // non-null
m.setCreateTime(System.currentTimeMillis());
m.setExpiresTime(System.currentTimeMillis() + ttlMs);
m.setIsValid(true);
m.checkByCanSaved(); // passes silently now

Type guard

boolean isSavable(ApiKeyModel m) { return SaFoxUtil.isNotEmpty(m.getApiKey()) && m.getLoginId() != null && m.getCreateTime() > 0 && m.getExpiresTime() > 0 && m.getIsValid() != null; }

Try / catch

try { manager.save(model); } catch (ApiKeyException e) { if (e.getCode() == SaApiKeyErrorCode.CODE_12304) { // map to 400 validation error using e.getMessage() } else throw e; }

Prevention

When it happens

Trigger: Building an ApiKeyModel manually and calling save/create without setting apiKey — e.g. constructing new ApiKeyModel(), setting loginId and times, then calling the manager's create/save which invokes checkByCanSaved(). Only this first check yields the 'ApiKey 值不可为空' message; a null apiKey from a client-supplied payload hits it directly.

Common situations: Integrating the sa-token-apikey plugin and hand-assembling the model instead of letting the framework generate the key; trimming/normalizing a client-provided key to empty string before save; API payloads where apiKey is optional on input but required at persistence.

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/088f5d451024a3fe. Report an issue: GitHub.