{"record":{"id":"56db0134ba9912a6","repo":"langchain-ai/deepagents","slug":"ptc-tool-name-tool-name-r-cannot-be-exposed-as-j","errorCode":null,"errorMessage":"PTC tool name {tool.name!r} cannot be exposed as JavaScript identifier {camel!r}. Tool names must map to `/^[A-Za-z_$][A-Za-z0-9_$]*$/`.","messagePattern":"PTC tool name (.+?) cannot be exposed as JavaScript identifier (.+?)\\. Tool names must map to `/\\^\\[A-Za-z_\\$\\]\\[A-Za-z0-9_\\$\\]\\*\\$/`\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/partners/quickjs/langchain_quickjs/_ptc.py","lineNumber":144,"sourceCode":"    return _prompt.is_valid_js_identifier(name)\n\n\ndef is_valid_ptc_tool_name(name: str) -> bool:\n    \"\"\"Return whether a tool can be exposed as `tools.<camelCaseName>`.\"\"\"\n    return _prompt.is_valid_ptc_tool_name(name)\n\n\ndef _raise_on_invalid_ptc_tools(tools: Sequence[BaseTool]) -> None:\n    for tool in tools:\n        camel = to_camel_case(tool.name)\n        if is_valid_js_identifier(camel):\n            continue\n        msg = (\n            f\"PTC tool name {tool.name!r} cannot be exposed as JavaScript \"\n            f\"identifier {camel!r}. Tool names must map to \"\n            \"`/^[A-Za-z_$][A-Za-z0-9_$]*$/`.\"\n        )\n        raise ValueError(msg)\n\n\ndef render_ptc_prompt(tools: Sequence[BaseTool], *, tool_name: str = \"eval\") -> str:\n    \"\"\"Build the `tools` namespace section of the system prompt.\"\"\"\n    if not tools:\n        return \"\"\n    _raise_on_invalid_ptc_tools(tools)\n    return _prompt.render_ptc_prompt(tools, tool_name=tool_name)\n","sourceCodeStart":126,"sourceCodeEnd":153,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/partners/quickjs/langchain_quickjs/_ptc.py#L126-L153","documentation":"Each PTC tool is exposed in JavaScript as a camelCase identifier; a tool whose name cannot be converted to a valid JS identifier (must match `/^[A-Za-z_$][A-Za-z0-9_$]*$/`) would generate broken/unreachable JS bindings, so it is rejected with ValueError during PTC tool validation or prompt rendering.","triggerScenarios":"Calling `filter_tools_for_ptc` or `render_ptc_prompt` with a tool whose name, after camelCase conversion, starts with a digit, contains characters like `-`, `.`, `/`, or unicode, or is empty.","commonSituations":"Tool names derived from HTTP routes or file paths (`/search/web`, `my-tool.v2`); names starting with digits (`3d_render`); dynamically generated tool names from user input.","solutions":["Rename the tool so it is alphanumeric snake_case starting with a letter (e.g. `web_search` instead of `/search/web`)","Set an explicit JS-safe tool name via the tool's name/alias when registering","Sanitize third-party tool names before passing them into a PTC-enabled agent"],"exampleFix":"# before\n@tool\ndef 3d-render(query: str) -> str: ...\n# after\n@tool\ndef render_3d(query: str) -> str: ...","handlingStrategy":"validation","validationCode":"import re\n_JS_IDENT = re.compile(r\"^[A-Za-z_$][A-Za-z0-9_$]*$\")\nfor t in tools:\n    camel = to_camel_case(t.name)\n    if not _JS_IDENT.match(camel):\n        raise ValueError(f\"tool {t.name!r} -> {camel!r} is not a valid JS identifier\")","typeGuard":"def is_js_safe_tool_name(name: str) -> bool:\n    camel = to_camel_case(name)\n    return bool(re.fullmatch(r\"[A-Za-z_$][A-Za-z0-9_$]*\", camel))","tryCatchPattern":"try:\n    selected = filter_tools_for_ptc(tools, config)\nexcept ValueError as e:\n    if \"JavaScript identifier\" in str(e):\n        tools = [rename_tool(t, sanitize_js_name(t.name)) for t in tools]\n        selected = filter_tools_for_ptc(tools, config)\n    else:\n        raise","preventionTips":["Name tools with lowercase snake_case identifiers starting with a letter","Sanitize names derived from routes, paths, or user input before tool registration","Run render_ptc_prompt on all PTC tool sets in tests to catch naming issues early"],"tags":["ptc","javascript","naming","tools"],"backgroundTag":"invalid-identifier-name","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}