Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/13009.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix runtime variant creation storing a JSON `null` model definition that made created variants unreadable via the v2 API, and backfill existing rows
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""backfill jsonb null default_model_definition in runtime_variants

Runtime variants created through the create API stored a JSON ``null`` in
``runtime_variants.default_model_definition``: the creator never set the
attribute and SQLAlchemy's JSON type serializes Python ``None`` as JSON
``null`` rather than SQL ``NULL``, so it slipped past the NOT NULL
constraint. Such rows load back as ``None`` and fail the node conversion,
which requires a model definition value. The creator now seeds an empty
draft (``{}``); this migration backfills the already-materialized JSON
``null`` rows with the same empty draft. ``{}`` (not ``{"models": null}``)
keeps every field truly unset, consistent with the exclude_unset write path
established by revision 2ec0aa5a19cf.

Revision ID: a0a28251f296
Revises: e5b71c94d2a8
Create Date: 2026-07-22 09:17:13.529025

"""

from alembic import op

# revision identifiers, used by Alembic.
revision = "a0a28251f296"
down_revision = "e5b71c94d2a8"
branch_labels = None
depends_on = None
# Part of: NEXT_RELEASE_VERSION


def upgrade() -> None:
op.execute(
"UPDATE runtime_variants"
" SET default_model_definition = '{}'::jsonb"
" WHERE default_model_definition = 'null'::jsonb"
)


def downgrade() -> None:
# The JSON null values carried no information (never-set attribute
# artifacts), so there is nothing to restore.
pass
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from dataclasses import dataclass
from typing import override

from ai.backend.common.config import ModelDefinitionDraft
from ai.backend.manager.errors.repository import UniqueConstraintViolationError
from ai.backend.manager.errors.resource import RuntimeVariantConflict
from ai.backend.manager.models.runtime_variant.row import RuntimeVariantRow
Expand Down Expand Up @@ -31,4 +32,5 @@ def build_row(self) -> RuntimeVariantRow:
row = RuntimeVariantRow()
row.name = self.name
row.description = self.description
row.default_model_definition = ModelDefinitionDraft()
return row
9 changes: 7 additions & 2 deletions tests/component/scheduling_history/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

from unittest.mock import MagicMock
from unittest.mock import AsyncMock

import pytest

from ai.backend.manager.actions.validators import ActionValidators
from ai.backend.manager.actions.validators.rbac import RBACValidators
from ai.backend.manager.api.rest.routing import RouteRegistry

# Statically imported so that Pants includes these modules in the test PEX.
Expand All @@ -30,7 +31,11 @@ def scheduling_history_processors(
repo = SchedulingHistoryRepository(database_engine)
service = SchedulingHistoryService(repo)
return SchedulingHistoryProcessors(
service=service, action_monitors=[], validators=MagicMock(spec=ActionValidators)
service=service,
action_monitors=[],
validators=ActionValidators(
rbac=RBACValidators(scope=AsyncMock(), single_entity=AsyncMock(), bulk=AsyncMock()),
),
)


Expand Down
Loading