github/copilot-sdk · error · IllegalArgumentException

Duplicate parameter name ' + param.name() + ' in tool ' +…

Error message

Duplicate parameter name ' + param.name() + ' in tool ' + toolName + '

What it means

Thrown by ParamSchema.buildSchema when two Param descriptors in the same tool share the same name. Duplicate names would produce ambiguous JSON schema properties and undefined argument binding, so validation rejects the tool registration up front.

Solutions

  1. Rename one of the duplicate Params so every name in the tool is unique
  2. Deduplicate before building: keep the first (or last) Param per name via a LinkedHashMap
  3. Add a unit test asserting buildSchema succeeds for every registered tool
  4. Catch IllegalArgumentException; the message names the offending parameter and tool

Example fix

// before
params.add(Param.of("path", String.class));
params.add(Param.of("path", String.class)); // duplicate
// after
params.add(Param.of("path", String.class));
params.add(Param.of("targetPath", String.class));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>(); for (Param<?> p : params) { if (!seen.add(p.name())) throw new IllegalStateException("duplicate " + p.name()); }

Type guard

boolean namesUnique(List<Param<?>> ps) { return ps.stream().map(Param::name).distinct().count() == ps.size(); }

Try / catch

try { schema = ParamSchema.buildSchema(toolName, params); } catch (IllegalArgumentException e) { /* message names the duplicate param and tool */ throw new ToolRegistrationException(toolName, e); }

Prevention

When it happens

Trigger: Calling buildSchema with a params list where two Params have identical name() values — e.g. copying a Param and forgetting to rename it, or merging parameter lists from two sources.

Common situations: Code generation or copy-paste duplication of parameter declarations; combining a base tool's params with an override list that repeats a name; refactors renaming the Java field but not the Param name.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/354e4cab8541dbb6. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ParamSchema.java:79

     *            zero or more parameter descriptors
     * @return a JSON Schema object map with {@code type=object},
     *         {@code properties}, and {@code required} keys
     * @throws IllegalArgumentException
     *             if a null param or duplicate parameter names are found
     */
    static Map<String, Object> buildSchema(String toolName, ObjectMapper mapper, Param<?>... params) {
        if (params == null || params.length == 0) {
            return Map.of("type", "object", "properties", Map.of(), "required", List.of());
        }

        // Validate: no null params, no duplicate names
        Set<String> seen = new HashSet<>();
        for (Param<?> param : params) {
            if (param == null) {
                throw new IllegalArgumentException("A Param descriptor is null for tool '" + toolName + "'");
            }
            if (!seen.add(param.name())) {
                throw new IllegalArgumentException(
                        "Duplicate parameter name '" + param.name() + "' in tool '" + toolName + "'");
            }
        }

        List<String> requiredNames = new ArrayList<>();
        Map<String, Object> properties = new LinkedHashMap<>();

        for (Param<?> param : params) {
            Map<String, Object> typeSchema;
            if (!param.schema().isEmpty()) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> parsed = mapper.readerFor(Map.class)
                            .with(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
                            .with(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS).readValue(param.schema());
                    typeSchema = parsed;
                } catch (Exception e) {
                    throw new IllegalArgumentException("Invalid schema JSON for parameter '" + param.name()

View on GitHub (pinned to cd8cf15dc3)