{"record":{"id":"6667d806d183ac3e","repo":"Tencent/APIJSON","slug":"raw-value-value-key-key-value-v-6667d8","errorCode":null,"errorMessage":"@raw:value 的 value 中 {key} 不合法！对应的 {key}:value 中 value 值 {value} 未在后端 RAW_MAP 中配置 ！","messagePattern":"@raw:value 的 value 中 (.+?) 不合法！对应的 (.+?):value 中 value 值 (.+?) 未在后端 RAW_MAP 中配置 ！","errorType":"validation","errorClass":"UnsupportedOperationException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":2246,"sourceCode":"\t */\n\t@Override\n\tpublic String gainRawSQL(String key, Object value, boolean throwWhenMissing) throws Exception {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tList<String> rawList = getRaw();\n\t\tboolean containRaw = rawList != null && rawList.contains(key);\n\t\tif (containRaw && value instanceof String == false) {\n\t\t\tthrow new UnsupportedOperationException(\"@raw:value 的 value 中 \" + key + \" 不合法！\"\n\t\t\t\t\t+ \"对应的 \" + key + \":value 中 value 类型只能为 String！\");\n\t\t}\n\n\t\tString rawSQL = containRaw ? RAW_MAP.get(value) : null;\n\t\tif (containRaw) {\n\t\t\tif (rawSQL == null) {\n\t\t\t\tif (throwWhenMissing) {\n\t\t\t\t\tthrow new UnsupportedOperationException(\"@raw:value 的 value 中 \" + key + \" 不合法！\"\n\t\t\t\t\t\t\t+ \"对应的 \" + key + \":value 中 value 值 \" + value + \" 未在后端 RAW_MAP 中配置 ！\");\n\t\t\t\t}\n\n\t\t\t\tputWarnIfNeed(JSONMap.KEY_RAW, \"@raw:value 的 value 中 \"\n\t\t\t\t\t\t\t+ key + \" 不合法！对应的 \" + key + \":value 中 value 值 \" + value + \" 未在后端 RAW_MAP 中配置 ！\");\n\t\t\t}\n\t\t\telse if (rawSQL.isEmpty()) {\n\t\t\t\treturn (String) value;\n\t\t\t}\n\t\t}\n\n\t\treturn rawSQL;\n\t}\n\n\n\t@Override\n\tpublic List<String> getJson() {\n\t\treturn json;","sourceCodeStart":2228,"sourceCodeEnd":2264,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L2228-L2264","documentation":"gainRawSQL with throwWhenMissing: the @raw-flagged value is a String but is not a key in the backend RAW_MAP (or maps to nothing). RAW_MAP is the server-side whitelist that turns a client token into fixed SQL; an unconfigured token is refused rather than passed through, preventing arbitrary SQL.","triggerScenarios":"{\"@raw\": \"@column\", \"@column\": \"customExpr\"} where customExpr was never added to RAW_MAP on the server; using a token valid on one deployment against another that lacks it.","commonSituations":"Environment drift: token configured in dev RAW_MAP but not production; upgrading APIJSON resets a programmatically-built RAW_MAP; typo between the token in code and the map key.","solutions":["Backend: add the token to RAW_MAP (e.g. RAW_MAP.put(\"customExpr\", \"toYYYYMM(date)\")) and reload","Use only tokens you know are configured; expose the available tokens to the frontend","If throwWhenMissing is false in your path this becomes a warning instead — but do not rely on that for writes"],"exampleFix":"// backend: APIJSONApplication.init() \n// AbstractSQLConfig.RAW_MAP.put(\"ymExpr\", \"toYYYYMM(created_at)\");\n// request: {\"@raw\": \"@column\", \"@column\": \"ymExpr\"}","handlingStrategy":"validation","validationCode":"const RAW_TOKENS = new Set(['ymExpr', 'statusCase']); // mirror of backend RAW_MAP keys\nfor (const k of rawListOf(obj)) {\n  const tok = obj[k];\n  if (typeof tok === 'string' && !RAW_TOKENS.has(tok)) throw new Error(`@raw token '${tok}' is not configured in backend RAW_MAP`);\n}","typeGuard":"const isKnownRawToken = (tok, known) => typeof tok === 'string' && known.has(tok);","tryCatchPattern":"try { await api.get(req); } catch (e) { if (e.message.includes('未在后端 RAW_MAP 中配置')) surfaceConfigErrorToAdmin(req, e); else throw e; }","preventionTips":["Keep the RAW_MAP token list in shared config consumed by both server and client","Add a startup check that logs all RAW_MAP keys; alert on env drift between deployments"],"tags":["apijson","raw","whitelist","config"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}