From 0dd5f34cf4a360ba9fab085ea7b5ed2cd507202a Mon Sep 17 00:00:00 2001 From: alamin-br Date: Tue, 2 Jun 2026 12:38:40 +0200 Subject: [PATCH] fix(backend): server error when creating or importing a table with malformed data (#5443) * fix(backend): server error when creating or importing a table with malformed data * fix: missing issue number in changelog --- .../database/api/tables/serializers.py | 2 + .../database/api/tables/test_table_views.py | 74 +++++++++++++++++++ ...en_creating_or_importing_a__table_wit.json | 9 +++ 3 files changed, 85 insertions(+) create mode 100644 changelog/entries/unreleased/bug/fixes_a_server_error_when_creating_or_importing_a__table_wit.json diff --git a/backend/src/baserow/contrib/database/api/tables/serializers.py b/backend/src/baserow/contrib/database/api/tables/serializers.py index 828e8e8b94..8869f994c4 100644 --- a/backend/src/baserow/contrib/database/api/tables/serializers.py +++ b/backend/src/baserow/contrib/database/api/tables/serializers.py @@ -102,6 +102,7 @@ class TableCreateSerializer(serializers.ModelSerializer): data = serializers.ListField( min_length=1, default=None, + child=serializers.ListField(allow_empty=False), help_text=( "A list of rows that needs to be created as initial table data. " "Each row is a list of values that are going to be added in the new " @@ -152,6 +153,7 @@ class TableImportSerializer(serializers.Serializer): data = serializers.ListField( min_length=1, required=True, + child=serializers.ListField(allow_empty=False), help_text=( "A list of rows you want to add to the specified table. " "Each row is a list of values, one for each **writable** field. " diff --git a/backend/tests/baserow/contrib/database/api/tables/test_table_views.py b/backend/tests/baserow/contrib/database/api/tables/test_table_views.py index 3aa7569857..4e89566752 100644 --- a/backend/tests/baserow/contrib/database/api/tables/test_table_views.py +++ b/backend/tests/baserow/contrib/database/api/tables/test_table_views.py @@ -485,6 +485,56 @@ def test_create_table_with_data( ] +@pytest.mark.django_db(transaction=True) +@pytest.mark.parametrize( + "invalid_data", + [[None], [1], ["string"], [[]]], +) +def test_create_table_with_invalid_data_shape_async( + api_client, data_fixture, patch_filefield_storage, invalid_data +): + user, token = data_fixture.create_user_and_token() + database = data_fixture.create_database_application(user=user) + url = reverse( + "api:database:tables:async_create", kwargs={"database_id": database.id} + ) + + with patch_filefield_storage(): + response = api_client.post( + url, + {"name": "Test", "data": invalid_data, "first_row_header": False}, + format="json", + HTTP_AUTHORIZATION=f"JWT {token}", + ) + + assert response.status_code == HTTP_400_BAD_REQUEST + assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION" + + +@pytest.mark.django_db(transaction=True) +@pytest.mark.parametrize( + "invalid_data", + [[None], [1], ["string"], [[]]], +) +def test_create_table_with_invalid_data_shape_sync( + api_client, data_fixture, patch_filefield_storage, invalid_data +): + user, token = data_fixture.create_user_and_token() + database = data_fixture.create_database_application(user=user) + url = reverse("api:database:tables:list", kwargs={"database_id": database.id}) + + with patch_filefield_storage(): + response = api_client.post( + url, + {"name": "Test", "data": invalid_data, "first_row_header": False}, + format="json", + HTTP_AUTHORIZATION=f"JWT {token}", + ) + + assert response.status_code == HTTP_400_BAD_REQUEST + assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION" + + @pytest.mark.django_db(transaction=True) def test_create_table_with_data_sync(api_client, data_fixture, patch_filefield_storage): user, token = data_fixture.create_user_and_token() @@ -1018,3 +1068,27 @@ def test_import_table_call(api_client, data_fixture): }, }, } + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "invalid_data", + [[None], [1], ["string"], [[]]], +) +def test_import_table_with_invalid_data_shape(api_client, data_fixture, invalid_data): + user, token = data_fixture.create_user_and_token() + database = data_fixture.create_database_application(user=user) + table = data_fixture.create_database_table(database=database) + data_fixture.create_text_field(table=table, user=user) + + url = reverse("api:database:tables:import_async", kwargs={"table_id": table.id}) + + response = api_client.post( + url, + HTTP_AUTHORIZATION=f"JWT {token}", + data={"data": invalid_data}, + format="json", + ) + + assert response.status_code == HTTP_400_BAD_REQUEST + assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION" diff --git a/changelog/entries/unreleased/bug/fixes_a_server_error_when_creating_or_importing_a__table_wit.json b/changelog/entries/unreleased/bug/fixes_a_server_error_when_creating_or_importing_a__table_wit.json new file mode 100644 index 0000000000..ce2b851c1e --- /dev/null +++ b/changelog/entries/unreleased/bug/fixes_a_server_error_when_creating_or_importing_a__table_wit.json @@ -0,0 +1,9 @@ +{ + "type": "bug", + "message": "Fixes a server error when creating or importing a table with malformed data", + "issue_origin": "github", + "issue_number": 3950, + "domain": "database", + "bullet_points": [], + "created_at": "2026-06-01" +}