diff --git a/requirements.txt b/requirements.txt
index 90f7561..2c167bc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
Flask==3.0.3
-pyxform==2.0.3
-gunicorn==22.0.0
+pyxform==2.1.0
+gunicorn==23.0.0
diff --git a/test.sh b/test.sh
index b8de17f..7b6c42e 100755
--- a/test.sh
+++ b/test.sh
@@ -33,15 +33,16 @@ if [ "$test_3_actual" != "$test_3_expected" ]; then
test_failed="true"
fi
-test_4_actual=$(curl --silent --request POST --header "X-XlsForm-FormId-Fallback: validate-error" --data-binary @test/validate-error.xlsx http://127.0.0.1:5001/api/v1/convert)
-test_4_expected='{"error":"ODK Validate Errors:\n>> Something broke the parser. See above for a hint.\nError evaluating field '\''concat'\'' (${concat}[1]): The problem was located in Calculate expression for ${concat}\nXPath evaluation: cannot handle function '\''concatx'\''\nCaused by: org.javarosa.xpath.XPathUnhandledException: The problem was located in Calculate expression for ${concat}\nXPath evaluation: cannot handle function '\''concatx'\''\n\t... 10 more\n\nThe following files failed validation:\n${validate-error}.xml\n\nResult: Invalid","itemsets":null,"result":null,"status":400,"warnings":null}'
+# test removes tmp file name from actual and expected
+test_4_actual=$(curl --silent --request POST --data-binary @test/validate-error.xlsx http://127.0.0.1:5001/api/v1/convert | sed 's/tmp[0-9a-z]\{8\}//g')
+test_4_expected=$(echo '{"error":"ODK Validate Errors:\n>> Something broke the parser.\nError evaluating field '\''concat'\'' (${concat}[1]): The problem was located in Calculate expression for ${concat}\nXPath evaluation: cannot handle function '\''concatx'\''\nCaused by: org.javarosa.xpath.XPathUnhandledException: The problem was located in Calculate expression for ${concat}\nXPath evaluation: cannot handle function '\''concatx'\''\n\t... 10 more\n\nThe following files failed validation:\n${}\n\nResult: Invalid","itemsets":null,"result":null,"status":400,"warnings":null}' | sed 's/tmp[0-9a-z]\{8\}//g')
if [ "$test_4_actual" != "$test_4_expected" ]; then
echo "test 4 failed: form that passes pyxform's internal checks, but fails ODK Validate's checks"
test_failed="true"
fi
test_5_actual=$(curl --silent --request POST --header "X-XlsForm-FormId-Fallback: external-choices" --data-binary @test/external-choices.xlsx http://127.0.0.1:5001/api/v1/convert)
-test_5_expected='{"error":null,"itemsets":"\"list_name\",\"name\",\"label\",\"province\",\"district\"\n\"districts\",\"district_a\",\"District A (in Province 1)\",\"province_1\",\"None\"\n\"districts\",\"district_b\",\"District B (in Province 1)\",\"province_1\",\"None\"\n\"districts\",\"district_c\",\"District C (in Province 2)\",\"province_2\",\"None\"\n\"None\",\"None\",\"None\",\"None\",\"None\"\n\"lots\",\"lot_10\",\"Lot 10 (in District A)\",\"province_1\",\"district_a\"\n\"lots\",\"lot_20\",\"Lot 20 (in District A)\",\"province_1\",\"district_a\"\n\"lots\",\"lot_30\",\"Lot 30 (In District B)\",\"province_1\",\"district_b\"\n\"lots\",\"lot_40\",\"Lot 40 (In District C)\",\"province_2\",\"district_c\"\n","result":"external-choicesprovince_1province_2","status":200,"warnings":[]}'
+test_5_expected='{"error":null,"itemsets":"\"list_name\",\"name\",\"label\",\"province\",\"district\"\n\"districts\",\"district_a\",\"District A (in Province 1)\",\"province_1\"\n\"districts\",\"district_b\",\"District B (in Province 1)\",\"province_1\"\n\"districts\",\"district_c\",\"District C (in Province 2)\",\"province_2\"\n\n\"lots\",\"lot_10\",\"Lot 10 (in District A)\",\"province_1\",\"district_a\"\n\"lots\",\"lot_20\",\"Lot 20 (in District A)\",\"province_1\",\"district_a\"\n\"lots\",\"lot_30\",\"Lot 30 (In District B)\",\"province_1\",\"district_b\"\n\"lots\",\"lot_40\",\"Lot 40 (In District C)\",\"province_2\",\"district_c\"\n","result":"external-choicesprovince_1province_2","status":200,"warnings":[]}'
if [ "$test_5_actual" != "$test_5_expected" ]; then
echo "test 5 failed: form that converts (with external choices)"
test_failed="true"