diff --git a/lib/api_form.dart b/lib/api_form.dart
index 4204213b..c83b945a 100644
--- a/lib/api_form.dart
+++ b/lib/api_form.dart
@@ -7,6 +7,7 @@ import "package:date_field/date_field.dart";
 
 import "package:inventree/api.dart";
 import "package:inventree/app_colors.dart";
+import 'package:inventree/helpers.dart';
 import "package:inventree/inventree/part.dart";
 import "package:inventree/inventree/sentry.dart";
 import "package:inventree/inventree/stock.dart";
@@ -201,7 +202,15 @@ class APIFormField {
 
   // Return the error message associated with this field
   List<String> errorMessages() {
-    List<dynamic> errors = (data["errors"] ?? []) as List<dynamic>;
+
+    dynamic errors = data["errors"] ?? [];
+
+    // Handle the case where a single error message is returned
+    if (errors is String) {
+      errors = [errors];
+    }
+
+    errors = errors as List<dynamic>;
 
     List<String> messages = [];
 
@@ -395,7 +404,7 @@ class APIFormField {
         helperStyle: _helperStyle(),
         hintText: placeholderText,
       ),
-      initialValue: (value ?? 0).toString(),
+      initialValue: simpleNumberString(double.tryParse(value.toString()) ?? 0),
       keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true),
       validator: (value) {
 
@@ -871,6 +880,8 @@ class _APIFormWidgetState extends State<APIFormWidget> {
 
   final IconData icon;
 
+  List<String> nonFieldErrors = [];
+
   List<APIFormField> fields;
 
   Function(Map<String, dynamic>)? onSuccess;
@@ -881,6 +892,29 @@ class _APIFormWidgetState extends State<APIFormWidget> {
 
     List<Widget> widgets = [];
 
+    // Display non-field errors first
+    if (nonFieldErrors.isNotEmpty) {
+      for (String error in nonFieldErrors) {
+        widgets.add(
+          ListTile(
+            title: Text(
+              error,
+              style: TextStyle(
+                color: COLOR_DANGER,
+              ),
+            ),
+            leading: FaIcon(
+              FontAwesomeIcons.exclamationCircle,
+              color: COLOR_DANGER
+            ),
+          )
+        );
+      }
+
+      widgets.add(Divider(height: 5));
+
+    }
+
     for (var field in fields) {
 
       if (field.hidden) {
@@ -982,7 +1016,36 @@ class _APIFormWidgetState extends State<APIFormWidget> {
 
       return response;
     }
+  }
 
+  void extractNonFieldErrors(APIResponse response) {
+
+    List<String> errors = [];
+
+    Map<String, dynamic> data = response.asMap();
+
+    // Potential keys representing non-field errors
+    List<String> keys = [
+      "__all__",
+      "non_field_errors",
+      "errors",
+    ];
+
+    for (String key in keys) {
+      if (data.containsKey(key)) {
+        dynamic result = data[key];
+
+        if (result is String) {
+          errors.add(result);
+        } else if (result is List) {
+          result.forEach((element) {
+            errors.add(element.toString());
+          });
+        }
+      }
+    }
+
+    nonFieldErrors = errors;
   }
 
   /*
@@ -1073,13 +1136,13 @@ class _APIFormWidgetState extends State<APIFormWidget> {
           success: false
         );
 
-        print(response.data);
-
         // Update field errors
         for (var field in fields) {
           field.extractErrorMessages(response);
         }
 
+        extractNonFieldErrors(response);
+
         break;
       case 401:
         showSnackIcon(
diff --git a/lib/helpers.dart b/lib/helpers.dart
new file mode 100644
index 00000000..942c98ec
--- /dev/null
+++ b/lib/helpers.dart
@@ -0,0 +1,13 @@
+/*
+ * A set of helper functions to reduce boilerplate code
+ */
+
+/*
+ * Simplify a numerical value into a string,
+ * supressing trailing zeroes
+ */
+String simpleNumberString(double number) {
+  // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart
+
+  return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1);
+}
\ No newline at end of file
diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart
index 82c37711..1aa709a7 100644
--- a/lib/inventree/stock.dart
+++ b/lib/inventree/stock.dart
@@ -1,6 +1,7 @@
 import "dart:async";
 
 import "package:intl/intl.dart";
+import 'package:inventree/helpers.dart';
 import "package:inventree/inventree/part.dart";
 import "package:flutter/cupertino.dart";
 
@@ -369,16 +370,11 @@ class InvenTreeStockItem extends InvenTreeModel {
 
   double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0;
 
-  String get quantityString {
+  String quantityString({bool includeUnits = false}){
 
-    String q = quantity.toString();
+    String q = simpleNumberString(quantity);
 
-    // Simplify integer values e.g. "1.0" becomes "1"
-    if (quantity.toInt() == quantity) {
-      q = quantity.toInt().toString();
-    }
-
-    if (units.isNotEmpty) {
+    if (includeUnits && units.isNotEmpty) {
       q += " ${units}";
     }
 
@@ -394,12 +390,7 @@ class InvenTreeStockItem extends InvenTreeModel {
       return "SN ${serialNumber}";
     }
 
-    // Is an integer?
-    if (quantity.toInt() == quantity) {
-      return "${quantity.toInt()}";
-    }
-
-    return "${quantity}";
+    return simpleNumberString(quantity);
   }
 
   String get locationName {
@@ -436,7 +427,7 @@ class InvenTreeStockItem extends InvenTreeModel {
     if (serialNumber.isNotEmpty) {
       return "SN: $serialNumber";
     } else {
-      return quantityString;
+      return simpleNumberString(quantity);
     }
   }
 
diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart
index c10ac170..2fa41ddb 100644
--- a/lib/widget/stock_detail.dart
+++ b/lib/widget/stock_detail.dart
@@ -622,7 +622,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
               title: Text(L10().countStock),
               leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK),
               onTap: _countStockDialog,
-              trailing: Text(item.quantityString),
+              trailing: Text(item.quantityString(includeUnits: true)),
           )
       );