From d7d0a5d921dd7d5bffa50f9c415c42f65a0267a4 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Wed, 22 Apr 2026 15:44:40 +0300 Subject: [PATCH] fix(settings): accept numeric values in update payload Svelte bind:value on coerces to a JS number, so the frontend sends {telegram_cache_ttl_hours: 0} after v0.2.4. Pydantic v2 won't auto-coerce int -> str, which produced a 422 on every save that touched a numeric setting. - Widen numeric fields to int | str | None in SettingsUpdate. - Normalize to str before persisting (DB column is text). --- .../src/notify_bridge_server/api/app_settings.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/server/src/notify_bridge_server/api/app_settings.py b/packages/server/src/notify_bridge_server/api/app_settings.py index 1ff8efa..d37d17e 100644 --- a/packages/server/src/notify_bridge_server/api/app_settings.py +++ b/packages/server/src/notify_bridge_server/api/app_settings.py @@ -56,10 +56,14 @@ async def get_setting(session: AsyncSession, key: str) -> str: class SettingsUpdate(BaseModel): + # Numeric fields declared as int|str so clients can send either form. + # Svelte's bind:value on coerces to a JS number, + # so the frontend sends ints for these; older/manual clients may send + # strings. We normalize to str before persisting. external_url: str | None = None telegram_webhook_secret: str | None = None - telegram_cache_ttl_hours: str | None = None - telegram_asset_cache_max_entries: str | None = None + telegram_cache_ttl_hours: int | str | None = None + telegram_asset_cache_max_entries: int | str | None = None supported_locales: str | None = None timezone: str | None = None @@ -95,11 +99,12 @@ async def update_settings( value = getattr(body, key, None) if value is None: continue + value_str = str(value) row = await session.get(AppSetting, key) if row: - row.value = value + row.value = value_str else: - row = AppSetting(key=key, value=value) + row = AppSetting(key=key, value=value_str) session.add(row) await session.commit()