github/copilot-sdk · error · IllegalArgumentException

required=true cannot be combined with a non-empty…

Error message

required=true cannot be combined with a non-empty defaultValue

What it means

Param's constructor enforces mutual exclusivity between required=true and a non-empty defaultValue: a parameter cannot be both mandatory and have a default. If the builder/constructor receives required=true together with a defaultValue string that is non-empty after null-coalescing, it throws this IllegalArgumentException. This is a declarative API contract check, not a parse-time issue.

Solutions

  1. Set required=false if the parameter should fall back to the defaultValue.
  2. Remove the defaultValue (pass null) if the parameter is genuinely required.
  3. Add a unit test over Param declarations to catch this combination at startup.

Example fix

// before
new Param("count", "desc", Type.INT, "5", true, null);
// after
new Param("count", "desc", Type.INT, null, true, null);
Defensive patterns

Strategy: validation

Validate before calling

static Param safeParam(String name, String desc, Class<?> type, String defaultValue, boolean required, String schema) {
    if (required && defaultValue != null && !defaultValue.isEmpty())
        throw new IllegalArgumentException("param '" + name + "': required=true conflicts with defaultValue");
    return new Param(name, desc, type, defaultValue, required, schema);
}

Try / catch

try {
    registry.register(new Param(name, desc, type, def, required, schema));
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("required=true cannot be combined")) {
        registry.register(new Param(name, desc, type, null, required, schema)); // drop default
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: new Param(..., required=true, defaultValue="5", ...) or builder .required(true).defaultValue("5") on any Param used to declare a Copilot tool parameter.

Common situations: Copy-pasting a parameter definition and toggling required without clearing the default; assuming an empty-string default means 'no default' (it does — null coalesces to "" but any non-empty string conflicts).

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/tool/Param.java:52

    private final Class<T> type;
    private final String name;
    private final String description;
    private final boolean required;
    private final String defaultValue;
    private final String schema;

    private Param(Class<T> type, String name, String description, boolean required, String defaultValue,
            String schema) {
        this.type = Objects.requireNonNull(type, "type");
        this.name = requireNonBlank(name, "name");
        this.description = requireNonBlank(description, "description");
        this.defaultValue = defaultValue == null ? "" : defaultValue;
        this.schema = schema == null ? "" : schema;
        this.required = required;

        if (this.required && !this.defaultValue.isEmpty()) {
            throw new IllegalArgumentException("required=true cannot be combined with a non-empty defaultValue");
        }

        if (!this.schema.isEmpty()) {
            String trimmed = this.schema.trim();
            if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
                throw new IllegalArgumentException(
                        "schema must be a valid JSON object string (must start with '{' and end with '}')");
            }
            if (!this.defaultValue.isEmpty()) {
                throw new IllegalArgumentException(
                        "schema cannot be combined with defaultValue — express defaults inside the schema if needed");
            }
        }

        validateDefaultValue(type, this.defaultValue);
    }

    /**

View on GitHub (pinned to cd8cf15dc3)