Tencent/APIJSON · error · IllegalArgumentException

POST请求: 每一个 key:value 中的key都必须是1个单词!

Error message

POST请求: 每一个 key:value 中的key都必须是1个单词!

What it means

Thrown on POST in prepared mode when one of the keys to insert fails StringUtil.isName — every column key in the table object must be a single identifier word. Because prepared statements cannot parameterize column names, a malformed key cannot be safely quoted and is rejected outright.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java:2388

					}

					return "count(" + c0 + ")" + as + q + JSONResponse.KEY_COUNT + q;
				}
			}

			return "count(" + (onlyOne ? gainKey(c0) : "*") + ")" + as + q + JSONResponse.KEY_COUNT + q;
			//			return SQL.count(onlyOne && StringUtil.isName(column.get(0)) ? getKey(column.get(0)) : "*");
		case POST:
			if (column == null || column.isEmpty()) {
				throw new IllegalArgumentException("POST 请求必须在Table内设置要保存的 key:value !");
			}

			String s = "";
			boolean pfirst = true;
			for (String c : column) {
				if (isPrepared() && StringUtil.isName(c) == false) {
					// 不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
					throw new IllegalArgumentException("POST请求: 每一个 key:value 中的key都必须是1个单词!");
				}
				s += ((pfirst ? "" : ",") + gainKey(c));

				pfirst = false;
			}

			return "(" + s + ")";
		case GET:
		case GETS:
			String joinColumn = "";
			if (joinList != null) {
				boolean first = true;
				for (Join<T, M, L> join : joinList) {
					if (join.isAppJoin()) {
						continue;
					}

					SQLConfig<T, M, L> ocfg = join.getOnConfig();

View on GitHub (pinned to 5284052872)

Solutions

  1. Sanitize keys client-side: match /^[A-Za-z][A-Za-z0-9_]*$/ before adding them to the table object.
  2. If a column name legitimately contains special characters, wrap it in backticks in the key: "`my-col`" is handled elsewhere, but plain keys must be single words.
  3. Whitelist allowed column names per table on the server instead of accepting arbitrary keys.
  4. Log the offending key from the exception message to locate the producer.

Example fix

// before
{"User":{"first name":"Tom"}}
// after
{"User":{"first_name":"Tom"}}
Defensive patterns

Strategy: validation

Validate before calling

const NAME = /^[A-Za-z][A-Za-z0-9_]*$/;
for (const k of Object.keys(table)) { if (!k.startsWith('@') && !NAME.test(k)) throw new Error('key not a word: ' + k); }

Type guard

function isInsertKey(k) { return /^[@`]/.test(k) || /^[A-Za-z][A-Za-z0-9_]*$/.test(k); }

Try / catch

catch IllegalArgumentException; reject request client-side once keys are validated

Prevention

When it happens

Trigger: POST body {"User":{"user name":"x"}} (space in key), {"User":{"user.id":1}} (dot), {"User":{"123abc":1}} (leading digit), or keys containing operators/quotes injected via user input mapped directly to JSON keys.

Common situations: Dynamically building the POST body from a map whose keys come from user input or a spreadsheet header; key/value confusion where a value ends up as a key; Unicode or invisible whitespace in keys copied from documents.

Related errors


AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14). Data as JSON: /api/errors/77d32863877a6800. Report an issue: GitHub.