jumpserver/jumpserver · error · ValidationError

path_params and query_params must be objects.

Error message

path_params and query_params must be objects.

What it means

Inside the arguments object, the path_params and query_params entries must themselves be dicts (or absent, which defaults to {}). If either is a list, string, scalar, or null-with-truthy issues, build rejects the whole payload with this error before parameter processing starts.

Source

Thrown at apps/chat_ai/executor/request_builder.py:161

                    flattened = []
                    for key, item in value.items():
                        flattened.extend((str(key), self._query_scalar(item)))
                    serialized.append((name, ','.join(flattened)))
                else:
                    raise ValidationError({f'query_params.{name}': f'Unsupported query style: {style}.'})
                continue

            serialized.append((name, self._query_scalar(value)))
        return serialized

    def build(self, operation, arguments):
        if not isinstance(arguments, dict):
            raise ValidationError({'arguments': 'Must be an object.'})
        path_params = arguments.get('path_params') or {}
        query_params = arguments.get('query_params') or {}
        body = arguments.get('body', {})
        if not isinstance(path_params, dict) or not isinstance(query_params, dict):
            raise ValidationError({'arguments': 'path_params and query_params must be objects.'})

        path = operation.path
        allowed_path = {item.get('name'): item for item in operation.path_parameters}
        for name, parameter in allowed_path.items():
            if parameter.get('required') and name not in path_params:
                raise ValidationError({'path_params': f'Missing required path parameter: {name}.'})
            if name in path_params:
                _validate_scalar(path_params[name], parameter.get('schema') or {}, f'path_params.{name}')
                path = path.replace('{' + name + '}', quote(str(path_params[name]), safe=''))
        unknown_path = sorted(set(path_params) - set(allowed_path))
        if unknown_path or '{' in path or '}' in path:
            raise ValidationError({'path_params': f'Invalid path parameters: {unknown_path}.'})

        allowed_query = {item.get('name'): item for item in operation.query_parameters}
        unknown_query = sorted(set(query_params) - set(allowed_query))
        if unknown_query:
            raise ValidationError({'query_params': f'Unknown query parameters: {", ".join(unknown_query)}.'})
        missing_query = sorted(

View on GitHub (pinned to 6ec464fabd)

Solutions

  1. Make path_params and query_params dicts of name→value, e.g. {'path_params': {'user_id': 123}, 'query_params': {'limit': 10}}
  2. Parse query-string style input into a dict (urllib.parse.parse_qs) before passing it in
  3. Adjust the tool's argument schema so the model is forced to emit objects for these fields

Example fix

# before
{'path_params': ['user_id', 123], 'query_params': 'limit=10'}

# after
{'path_params': {'user_id': 123}, 'query_params': {'limit': 10}}
Defensive patterns

Strategy: type-guard

Validate before calling

pp = arguments.get('path_params') or {}
qp = arguments.get('query_params') or {}
assert isinstance(pp, dict) and isinstance(qp, dict), 'path_params/query_params must be objects'

Type guard

def has_dict_param_containers(arguments) -> bool:
    return isinstance(arguments.get('path_params') or {}, dict) and isinstance(arguments.get('query_params') or {}, dict)

Try / catch

try:
    builder.build(operation, arguments)
except ValidationError as e:
    if 'must be objects' in e.errors.get('arguments', ''):
        arguments['query_params'] = dict(arguments['query_params'])  # e.g. from list of pairs
        result = builder.build(operation, arguments)
    else:
        raise

Prevention

When it happens

Trigger: arguments = {'path_params': ['/users', '123']} or {'query_params': 'limit=10'} — i.e. the nested containers are not objects. Also {'query_params': None} combined with a truthy path_params is fine (None falls back to {}), but any non-dict truthy value fails.

Common situations: LLMs emitting query strings instead of objects; specs where the model confuses the flat and nested argument layouts; hand-built test fixtures using tuples/lists of pairs.

Related errors


AI-assisted analysis of jumpserver/jumpserver@6ec464fabd (2026-08-28). Data as JSON: /api/errors/c021ab52581108f6. Report an issue: GitHub.