oraios/serena · error · ValueError

Cannot use both fixed_tools and excluded_tools/included_opti

Error message

Cannot use both fixed_tools and excluded_tools/included_optional_tools at the same time.

What it means

Serena tool configuration supports two mutually exclusive modes: a fixed explicit list of tools (fixed_tools) or an incremental delta on the default set (excluded_tools plus included_optional_tools). This ValueError is raised when both modes are configured simultaneously, since the combination is ambiguous.

Source

Thrown at src/serena/config/serena_config.py:168

    excluded_tools: Sequence[str] = ()
    """
    the names of tools to exclude from use [incremental mode]
    """
    included_optional_tools: Sequence[str] = ()
    """
    the names of optional tools to include [incremental mode]
    """
    fixed_tools: Sequence[str] = ()
    """
    the names of tools to use as a fixed set of tools [fixed mode]
    """

    def is_fixed_tool_set(self) -> bool:
        num_fixed = len(self.fixed_tools)
        num_incremental = len(self.excluded_tools) + len(self.included_optional_tools)
        if num_fixed > 0 and num_incremental > 0:
            raise ValueError("Cannot use both fixed_tools and excluded_tools/included_optional_tools at the same time.")
        return num_fixed > 0


@dataclass
class NamedToolInclusionDefinition(ToolInclusionDefinition):
    name: str | None = None

    def __str__(self) -> str:
        return f"ToolInclusionDefinition[{self.name}]"


@dataclass
class ModeSelectionDefinition:
    default_modes: Sequence[str] | None = None


@dataclass
class ModeSelectionDefinitionWithBaseModes(ModeSelectionDefinition):

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Pick one style: remove fixed_tools and keep excluded_tools/included_optional_tools, or remove those and specify only fixed_tools.
  2. If you intended an incremental change to the default toolset, list the desired tools in included_optional_tools/excluded_tools and empty fixed_tools.
  3. If you intended an explicit allowlist, move all tool names into fixed_tools and clear the other two lists.
  4. Check every active layer (context, mode, project config) since layers are combined and one layer may introduce the conflict.

Example fix

# before
tools:
  fixed_tools: [read_file, execute_shell_command]
  excluded_tools: [write_memory]
# after
tools:
  excluded_tools: [write_memory]
# or, for an explicit allowlist:
# tools:
#   fixed_tools: [read_file, execute_shell_command]
Defensive patterns

Strategy: validation

Validate before calling

def validate_tool_definition(tools: dict) -> None:
    fixed = len(tools.get("fixed_tools", []))
    incremental = len(tools.get("excluded_tools", [])) + len(tools.get("included_optional_tools", []))
    if fixed > 0 and incremental > 0:
        raise ValueError("Use either fixed_tools OR excluded_tools/included_optional_tools, not both.")

Type guard

def is_fixed_tool_set_cfg(tools: dict) -> bool:
    return len(tools.get("fixed_tools", [])) > 0 and not (tools.get("excluded_tools") or tools.get("included_optional_tools"))

Try / catch

try:
    tool_def.apply(backend)
except ValueError as e:
    if "fixed_tools" in str(e):
        tool_def.fixed_tools = []
        tool_def.apply(backend)
    else:
        raise

Prevention

When it happens

Trigger: Defining a tool definition (in serena_config.yml, a mode, or a context) where fixed_tools is non-empty AND excluded_tools or included_optional_tools is also non-empty; detected by is_fixed_tool_set() which is called during apply().

Common situations: Merging config fragments from different sources (e.g. combining a context that uses fixed_tools with a mode that excludes tools), editing YAML by hand and leaving leftover keys, or copying an example config that mixes the two styles.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/7771f8c45f3cb9f5. Report an issue: GitHub.