• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kobotoolbox / kpi / 25503822748
82%
master: 76%

Build:
Build:
LAST BUILD BRANCH: main
DEFAULT BRANCH: master
Ran 07 May 2026 03:07PM UTC
Jobs 9
Files 912
Run time 3min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

07 May 2026 02:59PM UTC coverage: 82.131% (-0.001%) from 82.132%
25503822748

push

github

web-flow
fix(formBuilder): null language on multilingual XLSForm save DEV-2095 (#7020)

### 📣 Summary

Opening the Form Builder fails with a "language needs to be configured"
error after saving a multilingual form (one with labels in multiple
languages and a `default_language` setting).

### 📖 Description

When a multilingual XLSForm (with labels in two or more languages and a
`default_language` set) is uploaded and then edited in the Form Builder,
saving the form once corrupts the language configuration. On the next
attempt to open the Form Builder, an error appears indicating a language
needs to be configured. Visiting "Manage Languages" shows an unknown
blank language has been created, and the form becomes uneditable.

### 💭 Notes

Root cause — frontend (unnullifyTranslations in formBuilderUtils.ts)

When the Form Builder loads, inputParser.parse() mutates its input
object to add translations_0 (the default language name), nullify
translations[0], and normalize settings from an array to an object.
Survey.loadDict was passing state.asset.content directly, so those
mutations landed on the live state.asset.content object. React Query's
background re-fetch then replaced state.asset with a fresh API response,
losing those mutations. launchAppForSurveyContent early-returns because
app is already initialised, so the mutations never run again. At save
time, unnullifyTranslations was reading state.asset.content, found
translations_0 = undefined, set defaultLang = null, and skipped the
rename — plain label keys reached the backend.

**Fix — frontend**

Pass clonedeep(assetContent) to Survey.loadDict so inputParser.parse()
mutates only the copy. state.asset.content stays as the raw API object;
any React Query re-fetch replaces it with identical data and no
mutations are lost.

At both save paths (previewForm and saveForm), pass
app.survey._initialParams to unnullifyTranslations instead of
state.asset.content. _initialParams is assigned at Survey construction
time dire... (continued)

7802 of 11998 branches covered (65.03%)

4 of 4 new or added lines in 1 file covered. (100.0%)

1244 existing lines in 84 files now uncovered.

29619 of 36063 relevant lines covered (82.13%)

5.17 hits per line

Coverage Regressions

Lines Coverage ∆ File
94
28.28
-31.65% kpi/views/v2/data.py
87
29.29
-62.14% kpi/serializers/v2/asset_file.py
72
49.02
-17.56% kobo/apps/audit_log/models.py
57
27.68
-50.89% kpi/utils/models.py
56
61.5
-26.29% kpi/permissions.py
55
61.11
-9.55% kpi/serializers/v2/asset.py
50
54.46
-24.75% kpi/filters.py
39
27.13
-30.23% kobo/apps/trash_bin/utils/trash.py
37
40.69
-6.1% kpi/deployment_backends/openrosa_backend.py
33
21.8
-24.81% kobo/apps/subsequences/models.py
31
37.57
-17.92% kpi/serializers/current_user.py
27
36.36
-49.09% kpi/views/v1/export_task.py
26
40.48
-20.63% kobo/apps/openrosa/apps/logger/signals.py
25
62.75
-7.0% kpi/views/v2/asset.py
24
65.01
-5.96% kpi/deployment_backends/base_backend.py
23
64.76
-21.9% kpi/utils/object_permission.py
22
50.98
-43.14% kpi/serializers/v2/asset_snapshot.py
22
55.56
-40.74% kpi/serializers/v2/permission.py
21
48.84
-48.84% kobo/apps/trash_bin/models/project.py
20
77.82
-3.36% kpi/models/import_export_task.py
19
42.5
-47.5% kpi/views/v1/import_task.py
19
49.25
-28.36% kpi/views/v2/user.py
18
42.33
-8.37% kpi/renderers.py
17
26.4
-4.78% kpi/serializers/v2/asset_permission_assignment.py
17
53.46
-7.83% kpi/utils/xml.py
16
55.81
-37.21% kpi/backends.py
16
43.7
-11.85% kpi/views/v2/asset_snapshot.py
14
25.0
-12.96% kobo/apps/openrosa/apps/logger/utils/instance.py
14
30.43
-60.87% kpi/utils/private_storage.py
13
49.47
-13.68% kpi/views/v2/asset_permission_assignment.py
12
90.24
-2.11% kpi/models/asset.py
12
75.0
-10.34% kpi/models/asset_snapshot.py
11
78.57
-13.1% kobo/apps/audit_log/base_views.py
11
78.16
-12.64% kobo/apps/audit_log/signals.py
11
28.57
-52.38% kobo/apps/trash_bin/utils/signals.py
11
44.12
-32.35% kpi/utils/rename_xls_sheet.py
11
75.0
-21.15% kpi/views/v2/asset_file.py
10
85.29
-9.8% kpi/models/asset_file.py
10
78.85
-19.23% kpi/serializers/v2/user.py
10
47.69
-15.38% kpi/utils/hash.py
10
57.14
-35.71% kpi/views/v1/asset.py
9
77.65
-3.53% kobo/apps/openrosa/apps/logger/xform_instance_parser.py
9
41.18
-52.94% kpi/utils/viewset_mixins.py
8
52.56
-10.26% kpi/authentication.py
7
37.6
-2.89% kobo/apps/subsequences/actions/base.py
7
52.38
-33.33% kpi/serializers/v2/reports.py
7
71.71
-3.41% kpi/utils/mongo_helper.py
7
63.33
-23.33% kpi/views/v2/asset_version.py
6
65.87
-4.76% kpi/utils/autoname.py
5
57.14
-17.86% kobo/apps/subsequences/utils/supplement_data.py
5
62.07
-5.75% kpi/tasks.py
5
40.0
-50.0% kpi/utils/fuzzy_int.py
5
86.21
-3.45% kpi/utils/query_parser/query_parser.py
5
44.44
-55.56% kpi/views/v1/submission.py
5
73.91
-21.74% kpi/views/v2/user_asset_subscription.py
4
32.0
-16.0% kobo/apps/openrosa/apps/logger/utils/attachment.py
4
70.05
-2.03% kpi/mixins/formpack_xlsform_utils.py
4
76.19
-19.05% kpi/serializers/v2/user_asset_subscription.py
3
0.0
-100.0% kobo/settings/testing_no_stripe.py
3
70.0
-30.0% kpi/fields/serializer_method_file.py
3
57.14
-42.86% kpi/views/v1/asset_version.py
3
84.21
-15.79% kpi/views/v2/permission.py
2
75.0
-1.02% kobo/apps/openrosa/apps/logger/models/instance.py
2
66.67
-13.33% kobo/apps/openrosa/apps/viewer/signals.py
2
60.0
-20.0% kpi/mixins/mfa.py
2
96.55
-2.3% kpi/utils/asset_content_analyzer.py
2
85.92
-2.82% kpi/utils/sluggify.py
1
75.0
-25.0% kobo/apps/audit_log/mixins.py
1
90.0
-10.0% kobo/apps/audit_log/utils.py
1
83.67
-2.04% kobo/apps/openrosa/apps/logger/exceptions.py
1
44.84
0.19% kobo/apps/openrosa/libs/utils/logger_tools.py
1
62.42
1.21% kobo/apps/organizations/models.py
1
92.31
0.0% kobo/apps/user_reports/utils/migrations.py
1
75.0
-25.0% kpi/fields/read_only.py
1
80.95
-4.76% kpi/fields/writable_json.py
1
94.15
-0.28% kpi/mixins/object_permission.py
1
66.67
-8.33% kpi/mixins/validation_password_permission.py
1
91.3
-4.35% kpi/serializers/v2/asset_version.py
1
85.71
-1.43% kpi/utils/cache.py
1
75.0
-25.0% kpi/utils/gravatar_url.py
1
96.67
-3.33% kpi/utils/project_views.py
1
91.67
-8.33% kpi/utils/strings.py
1
61.9
-2.38% kpi/utils/urls.py
1
55.56
-2.22% kpi/views/current_user.py
Jobs
ID Job ID Ran Files Coverage
1 25503822748.1 07 May 2026 03:07PM UTC 910
55.47
2 25503822748.2 07 May 2026 03:09PM UTC 910
65.98
3 25503822748.3 07 May 2026 03:09PM UTC 910
53.91
4 25503822748.4 07 May 2026 03:10PM UTC 908
52.69
5 25503822748.5 07 May 2026 03:10PM UTC 908
54.23
6 25503822748.6 07 May 2026 03:12PM UTC 910
54.26
7 25503822748.7 07 May 2026 03:30PM UTC 908
60.22
8 25503822748.8 07 May 2026 03:36PM UTC 908
52.93
9 25503822748.9 07 May 2026 03:42PM UTC 912
68.21
Source Files on build 25503822748
  • Tree
  • List 912
  • Changed 3
  • Source Changed 0
  • Coverage Changed 3
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • ccd7e1b2 on github
  • Prev Build on release/2.026.12 (#25370757232)
  • Next Build on release/2.026.12 (#25515255167)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc