lfnovo/open-notebook · error · RuntimeError
Failed to update record: {str(e)}
Error message
Failed to update record: {str(e)} What it means
repo_update() executes a SurrealQL UPDATE and wraps any exception as RuntimeError('Failed to update record: <cause>'). Unlike repo_create it embeds the cause in the message, so the text names the actual problem — commonly 'record not found', schema type mismatches, or fields not defined in the schema when the table is schemafull.
Source
Thrown at open_notebook/database/repository.py:205
_ensure_safe_identifier(table, "table")
if isinstance(id, RecordID):
record_id: RecordID = id
elif ":" in id and id.startswith(f"{table}:"):
record_id = ensure_record_id(id)
else:
record_id = RecordID(table, id)
data.pop("id", None)
if "created" in data and isinstance(data["created"], str):
data["created"] = datetime.fromisoformat(data["created"])
data["updated"] = datetime.now(timezone.utc)
query = "UPDATE $target MERGE $data;"
# logger.debug(f"Update query: {query}")
result = await repo_query(query, {"target": record_id, "data": data})
# if isinstance(result, list):
# return [_return_data(item) for item in result]
return parse_record_ids(result)
except Exception as e:
raise RuntimeError(f"Failed to update record: {str(e)}")
async def repo_delete(record_id: Union[str, RecordID]):
"""Delete a record by record id"""
try:
async with db_connection() as connection:
return await connection.delete(ensure_record_id(record_id))
except Exception as e:
logger.exception(e)
raise RuntimeError(f"Failed to delete record: {str(e)}")
async def repo_insert(
table: str, data: List[Dict[str, Any]], ignore_duplicates: bool = False
) -> List[Dict[str, Any]]:
"""Create a new record in the specified table"""
try:View on GitHub (pinned to a7de90d38a)
Solutions
- Read the appended cause text — it is the actual SurrealDB error
- If 'not found', verify the record still exists (repo_query by id) and refresh stale ids in the caller
- Ensure new model fields have a corresponding migration and payload values are JSON primitives (str/int/float/bool/list/dict, isoformat dates)
- Retry once if the failure was a transient connection issue
Example fix
// before
data = {"created_at": datetime.utcnow()}
await repo_update(record_id, data)
// after
data = {"created_at": datetime.utcnow().isoformat()}
await repo_update(record_id, data) Defensive patterns
Strategy: try-catch
Validate before calling
existing = await repo_query("SELECT id FROM type::table($t) WHERE id = $id", {'t': table, 'id': rid})
if not existing:
skip update # record gone Try / catch
try:
await repo_update(record_id, data)
except RuntimeError as e:
if 'not found' in str(e):
return None # treat as already deleted
raise Prevention
- Read the embedded cause text — repo_update includes it
- Normalize payloads (isoformat dates, str enums) before update
- Handle not-found as a benign case in concurrent workflows
When it happens
Trigger: Updating a record id that no longer exists; sending None where the schema requires a type; updating a field not present in a SCHEMAFULL table definition; serializing unsupported Python objects (datetime, enums) into the data dict.
Common situations: Concurrent deletes racing an update; stale record ids held in frontend state after another client deleted the row; model changes adding fields without a migration; passing raw datetime/Enum objects in the data payload.
Related errors
- Failed to create record
- Failed to update credential
- Search failed: {str(e)}
- Error updating transformation: {str(e)}
- Failed to load default models configuration
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/aa8e998d8283d00e.
Report an issue: GitHub.