oraios/serena · error · ValueError
symbol_info_budget must be a number or null, got: {symbol_in
Error message
symbol_info_budget must be a number or null, got: {symbol_info_budget_raw} What it means
_from_dict validates symbol_info_budget: it may be null (disabled) or a non-negative number, anything else raises ValueError. The budget controls how many symbols Serena reports per tool call, so the config parser coerces it to float and rejects negative values with a separate message.
Source
Thrown at src/serena/config/serena_config.py:613
) from e
# Validate activation_command_timeout
activation_command_timeout_raw = data.get("activation_command_timeout", 180.0)
try:
activation_command_timeout = float(activation_command_timeout_raw)
except (TypeError, ValueError) as e:
raise ValueError(f"activation_command_timeout must be a number, got: {activation_command_timeout_raw}") from e
if activation_command_timeout <= 0:
raise ValueError(f"activation_command_timeout must be positive, got: {activation_command_timeout}")
# Validate symbol_info_budget
symbol_info_budget_raw = data["symbol_info_budget"]
symbol_info_budget = symbol_info_budget_raw
if symbol_info_budget is not None:
try:
symbol_info_budget = float(symbol_info_budget_raw)
except (TypeError, ValueError) as e:
raise ValueError(f"symbol_info_budget must be a number or null, got: {symbol_info_budget_raw}") from e
if symbol_info_budget < 0:
raise ValueError(f"symbol_info_budget cannot be negative, got: {symbol_info_budget}")
language_backend_value = data.get("language_backend")
language_backend = LanguageBackend.from_str(language_backend_value) if language_backend_value else None
line_ending_value = data.get("line_ending")
line_ending = LineEnding.from_str(line_ending_value) if line_ending_value else None
# gracefully handle user errors: incorrect use of None/empty where a list is required
ignored_paths = data["ignored_paths"] or []
fixed_tools = data["fixed_tools"] or []
excluded_tools = data["excluded_tools"] or []
included_optional_tools = data["included_optional_tools"] or []
additional_workspace_folders = data.get("ls_additional_workspace_folders") or []
if "base_modes" in data and data["base_modes"] is not None:
log.warning("The base_modes setting in project.yml is deprecated and will be ignored.")View on GitHub (pinned to 7fcbca7e62)
Solutions
- Set symbol_info_budget to a non-negative number (e.g. symbol_info_budget: 50) or explicit null to disable the limit
- Convert string inputs before passing: float(value) if value not in (None, 'null') else None
- Ensure the key exists in project.yml (absent key raises KeyError, not this error)
- Check for negative values too — a following check rejects symbol_info_budget < 0
Example fix
// before (project.yml) symbol_info_budget: "unlimited" // after (project.yml) symbol_info_budget: 100
Defensive patterns
Strategy: type-guard
Validate before calling
raw = data.get("symbol_info_budget")
if raw is not None and not isinstance(raw, (int, float)):
raise TypeError(f"symbol_info_budget must be a number or null, got {raw!r}")
if raw is not None and float(raw) < 0:
raise ValueError(f"symbol_info_budget cannot be negative, got {raw}") Type guard
def is_number_or_none(v) -> bool:
return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool)) Try / catch
try:
config = ProjectConfig.load(project_root)
except ValueError as e:
if 'symbol_info_budget' in str(e):
logger.error("symbol_info_budget must be a number or null in project.yml: %s", e)
raise Prevention
- Write a plain number (e.g. 100) or explicit `null` in project.yml — never words like 'unlimited'
- Always include the key (missing key raises KeyError since it's read via data[...])
- Convert CLI/env string inputs to float or None before passing to autogenerate
- Remember negative numbers fail a separate check — clamp with max(0, value)
When it happens
Trigger: ProjectConfig.autogenerate(..., symbol_info_budget='unlimited') or a project.yml with symbol_info_budget: 'high' / true / a list; any non-numeric, non-null YAML scalar. Missing key raises KeyError instead since data['symbol_info_budget'] is accessed directly.
Common situations: Hand-editing project.yml with a descriptive word like 'default' or 'unlimited' instead of a number; passing a string from a CLI flag without conversion; YAML auto-typing surprises (e.g. `no` parsed as boolean False is fine as falsy? no — False is not None so float(False)=0.0, but 'none' string fails).
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
- activation_command_timeout must be a number, got: {activatio
- Cannot use both fixed_tools and excluded_tools/included_opti
- Unknown language backend '{backend_str}': valid values are {
- Invalid line_ending: {value!r}. Valid values are: {valid}
- Invalid language server: '{orig_language_str}'.\nValid value
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/2cd50d65eba50249.
Report an issue: GitHub.