{"record":{"id":"228ad60a6cdff253","repo":"sansan0/TrendRadar","slug":"keyword-228ad6","errorCode":null,"errorMessage":"keyword 必须是字符串类型","messagePattern":"keyword 必须是字符串类型","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":null,"severity":"error","filePath":"mcp_server/utils/validators.py","lineNumber":499,"sourceCode":"\ndef validate_keyword(keyword: str) -> str:\n    \"\"\"\n    验证关键词\n\n    Args:\n        keyword: 搜索关键词\n\n    Returns:\n        处理后的关键词\n\n    Raises:\n        InvalidParameterError: 关键词无效\n    \"\"\"\n    if not keyword:\n        raise InvalidParameterError(\"keyword 不能为空\")\n\n    if not isinstance(keyword, str):\n        raise InvalidParameterError(\"keyword 必须是字符串类型\")\n\n    keyword = keyword.strip()\n\n    if not keyword:\n        raise InvalidParameterError(\"keyword 不能为空白字符\")\n\n    if len(keyword) > 100:\n        raise InvalidParameterError(\n            \"keyword 长度不能超过100个字符\",\n            suggestion=\"请使用更简洁的关键词\"\n        )\n\n    return keyword\n\n\ndef validate_top_n(top_n: Optional[Union[int, str]], default: int = 10) -> int:\n    \"\"\"\n    验证TOP N参数","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/mcp_server/utils/validators.py#L481-L517","documentation":"Raised by validate_keyword when keyword is truthy but not a str — e.g. an int, dict, or list. Note the check ordering: only truthiness is checked first, so keyword: 123 (truthy non-string) reaches the isinstance check and raises here, while keyword: 0 or [] is caught by the earlier '不能为空' branch instead.","triggerScenarios":"Passing keyword: 123, keyword: [\"hot topics\"], or keyword: {\"text\": \"foo\"} — e.g. an LLM wrapping the term in a list, or client code passing an ID or parsed JSON object where a string is expected.","commonSituations":"LLM tool calls guessing array-typed parameters; clients forwarding unserialized form data; variable reuse where a number ends up in the keyword slot; JSON payloads where a string field accidentally becomes a nested structure.","solutions":["Pass a plain string: keyword: \"人工智能\" instead of [\"人工智能\"] or 123","Client-side, coerce with String(keyword) when it is a number, and unwrap single-element arrays","Validate the outbound payload against the tool schema before sending","In strict TypeScript/Pyright codebases, type the parameter as string so this fails at compile time"],"exampleFix":"// before\n{\"keyword\": [\"AI 芯片\"]}\n// after\n{\"keyword\": \"AI 芯片\"}","handlingStrategy":"type-guard","validationCode":"if (Array.isArray(keyword)) keyword = keyword[0];\nif (typeof keyword !== 'string') keyword = String(keyword); // or reject","typeGuard":"const isKeywordString = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try { call({ keyword }); }\ncatch (e) {\n  if (/keyword 必须是字符串类型/.test(e.message)) call({ keyword: String(keyword) });\n  else throw e;\n}","preventionTips":["Unwrap single-element arrays and coerce primitives at the adapter boundary","Type the field as string in client models/JSON schema","Inspect outbound payloads once in a devtools proxy when LLM clients mis-shape args"],"tags":["keyword","type-validation","string"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}