Skip to content

bug: agent creation crashes with opaque ValueError on non-integer CPU in template resources #1197

Description

@vybe

Summary

When an agent is created from a GitHub source repo whose template.yaml declares a non-integer CPU value (e.g. Kubernetes-style cpu: \"0.5\"), agent creation aborts with an opaque ValueError: invalid literal for int() with base 10: '0.5'. The repo-access validation, MCP key creation, subscription assignment and env-var setup all succeed first, then the container-create step crashes on a raw int(cpu). The platform should validate/normalize template resource fields and return a clear, actionable error instead of crashing with a cryptic Python message — and should not leave partial side effects behind.

Component

Backend / Agent Service (container creation)

Priority

P2 — agent creation from an otherwise-valid source repo fails; workaround exists (edit the template to a valid CPU value), but the failure mode is opaque and leaves orphaned rows.

Error

ERROR services.agent_service.crud: Failed to create agent [AGENT]: invalid literal for int() with base 10: '0.5'

Location

  • File: src/backend/services/agent_service/crud.py
  • Line: 741
  • Function/Class: container-create block in the agent create path
  • Same pattern (also unguarded):
    • src/backend/services/agent_service/lifecycle.py:554 — nano_cpus=int(cpu) * 1_000_000_000
    • src/backend/services/system_agent_service.py:248 — nano_cpus=int(resources.get(\"cpu\", \"4\")) * 1_000_000_000

Root Cause

The CPU value taken from the agent's template.yaml resources block is fed straight into int():

nano_cpus=int(config.resources.get('cpu') or _get_default_resource('cpu')) * 1_000_000_000,

A non-integer value such as cpu: "0.5" (or any Kubernetes-style spec) raises ValueError and aborts the entire create. There is no validation/normalization of template resource fields against the allowed set (cpu ∈ {1,2,4,8,16}, memory ∈ {1g,2g,4g,8g,16g,32g}) before they reach Docker.

The adjacent memory line has the same class of problem — it passes the raw value to Docker's mem_limit:

mem_limit=config.resources.get('memory') or _get_default_resource('memory'),

A Kubernetes-style memory: "512Mi" is not a valid Docker memory string (Docker expects 512m / 4g), so it would also fail; the int(cpu) error simply fires first.

Introduced by the #1126/#1128 change (apply CPU cgroup limit on Linux via nano_cpus), which added the unguarded int(cpu) at all three creation sites.

Reproduction Steps

  1. Create a GitHub repo whose template.yaml contains a Kubernetes-style resources block:
    resources:
      cpu: "0.5"
      memory: "512Mi"
  2. Create an agent pointed at that repo in source mode.
  3. Backend validates repo access, creates the MCP key, assigns a subscription, sets template env vars — then crashes at the nano_cpus conversion.
  4. Observe: opaque ValueError: invalid literal for int() with base 10: '0.5'. The agent_ownership row rolls back, but an orphaned mcp_api_keys row for the agent is left behind (one per attempt).

Suggested Fix

Validate and normalize resources.cpu and resources.memory against the allowed values before container creation, and raise a clear, actionable error on invalid input. Apply at all three creation sites (or factor into one shared helper):

VALID_CPU = {"1", "2", "4", "8", "16"}

def _normalize_cpu(value) -> str:
    cpu = str(value or _get_default_resource("cpu"))
    if cpu not in VALID_CPU:
        raise ValueError(
            f"Invalid cpu '{cpu}': must be one of {sorted(VALID_CPU, key=int)} (integer processors)"
        )
    return cpu

# at the call site:
nano_cpus=int(_normalize_cpu(config.resources.get('cpu'))) * 1_000_000_000,

Do the equivalent for memory (validate against {1g,2g,4g,8g,16g,32g}, or map common k8s suffixes → Docker form). Surfacing this as a 4xx validation error at the API boundary (rather than a 500 from deep in container creation) would be ideal.

Secondary: roll back the MCP key creation when create fails so a failed create leaves no orphan mcp_api_keys rows.

Environment

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions