Encountering 422 Error When Trying to Update Records in Airtable with Flutter

I’m facing an issue where I receive a 422 error when attempting to update records in my Airtable database using my Flutter application. The error message is [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception: 422. While I’m able to read and delete records without any problems, updates just refuse to go through, no matter how I approach it.

employee_service.dart

import 'package:http/http.dart' as http;
import 'package:myapp/models/employee_model.dart';
import 'package:myapp/config/app_config.dart';

class EmployeeService {
  final Uri baseUrl = Uri.https(
    "api.airtable.com",
    "/v0/${AppConfig.baseId}/employees",
    {"maxRecords": "100", "view": "Main view"},
  );

  Future<List<Employee>> fetchEmployees() async {
    final response = await http.get(
      baseUrl,
      headers: {"Authorization": "Bearer ${AppConfig.apiToken}"},
    );

    if (response.statusCode == 200) {
      var jsonData = jsonDecode(response.body);
      var records = jsonData['records'];
      List<Employee> employees = [];
      
      records.forEach((record) => {
        employees.add(
          Employee(
            recordId: record['id'],
            firstName: record['fields']['firstName'],
            lastName: record['fields']['lastName'],
            profileImage: record['fields']['profileImage'][0]['url'],
            status: record['fields']['status'],
            email: record['fields']['email'],
            city: record['fields']['city'],
            phone: record['fields']['phone'],
            approved: record['fields']['approved'],
            resume: record['fields']['resume'][0]['url'],
            latitude: record['fields']['latitude'].toDouble(),
            longitude: record['fields']['longitude'].toDouble(),
          ),
        )
      });

      return employees;
    } else {
      throw "Request failed";
    }
  }

  Future<String> removeEmployee(String recordId) async {
    final response = await http.delete(
      Uri.https("api.airtable.com", "/v0/${AppConfig.baseId}/employees/$recordId"),
      headers: {"Authorization": "Bearer ${AppConfig.apiToken}"},
    );

    if (response.statusCode == 200) {
      return recordId;
    } else {
      throw Exception(response.statusCode);
    }
  }

  Future<Employee> modifyEmployee(String recordId, String approvalStatus) async {
    final response = await http.patch(
      Uri.https("api.airtable.com", "/v0/${AppConfig.baseId}/employees/$recordId"),
      headers: {
        "Authorization": "Bearer ${AppConfig.apiToken}",
        "Content-Type": "application/json",
      },
      body: jsonEncode({
        'fields': {
          'approved': approvalStatus,
        }
      }),
    );

    if (response.statusCode == 200) {
      return Employee.fromJson(jsonDecode(response.body));
    } else {
      throw Exception(response.statusCode);
    }
  }
}

employee_model.dart

class Employee {
  String recordId;
  String firstName;
  String lastName;
  String profileImage;
  String status;
  String phone;
  String email;
  String city;
  String resume;
  String approved;
  double latitude;
  double longitude;

  Employee({
    required this.recordId,
    required this.firstName,
    required this.lastName,
    required this.profileImage,
    required this.status,
    required this.phone,
    required this.email,
    required this.city,
    required this.resume,
    required this.latitude,
    required this.longitude,
    required this.approved,
  });

  factory Employee.fromJson(Map<String, dynamic> data) {
    return Employee(
      recordId: data['id'],
      firstName: data['fields']['firstName'],
      lastName: data['fields']['lastName'],
      profileImage: data['fields']['profileImage'][0]['url'],
      status: data['fields']['status'],
      email: data['fields']['email'],
      city: data['fields']['city'],
      phone: data['fields']['phone'],
      approved: data['fields']['approved'],
      resume: data['fields']['resume'][0]['url'],
      latitude: data['fields']['latitude'].toDouble(),
      longitude: data['fields']['longitude'].toDouble(),
    );
  }
}

Can anyone help me understand what’s causing this 422 error? I’m completely stuck and would really appreciate any assistance!

hey! i totally get ur frustration with the 422 error. double check if ur field names are exactly same as in Airtable (case sensitive). also, the ‘approved’ field might need a specific data type. try logging the full response, not just the status to see what Airtable says.

I’ve hit this exact issue with Airtable’s API. That 422 error means validation failed on Airtable’s end. Usually happens when your field has validation rules that your data doesn’t match. Check your ‘approved’ field in the base - does it have specific allowed values or data type restrictions? If it’s a single select field, you need to use one of the exact predefined options. Add some logging to your catch block to see Airtable’s actual error message - way more helpful than just the status code. Also double-check that the record ID still exists and wasn’t deleted between your fetch and update.

Had the same issue last month - spent hours pulling my hair out! Check if your ‘approved’ field has specific formatting requirements or if it’s set up as a checkbox instead of text. Airtable’s picky about data types matching exactly what the field expects. Also double-check your API token has write permissions for that base and table. Try updating a simple text field first to see if it’s the ‘approved’ field causing problems or if all updates are failing.

I see what’s happening. Been dealing with Airtable APIs for years and that 422 is almost always field validation or data structure issues.

Check your modifyEmployee function. You’re sending approvalStatus as a string, but your ‘approved’ field is probably set up as a checkbox, not text. Checkbox fields want boolean values (true/false), not strings.

Try this:

body: jsonEncode({
  'fields': {
    'approved': approvalStatus == 'approved' ? true : false,
  }
}),

Also, add error logging to see what Airtable actually says:

if (response.statusCode != 200) {
  print('Error response: ${response.body}');
  throw Exception('${response.statusCode}: ${response.body}');
}

This shows you exactly which validation rule you’re breaking. I’ve wasted too many hours debugging API calls without seeing the actual server error.

If the approved field isn’t a checkbox, check if it’s a single select with predefined options. You’d need to match those exact values.

Wrestling with Airtable API quirks and HTTP errors gets old fast. Been there way too many times.

Yeah, you could debug those field validation issues everyone’s talking about. But think about what you’re actually doing - building manual HTTP calls, parsing responses, handling errors, dealing with API weirdness. That’s a ton of moving parts for something simple.

I’d skip the debugging headache and automate this with Latenode instead. Set up a workflow that handles Airtable updates properly, with error handling and field validation baked in. No more guessing about data types or fighting 422 errors.

The workflow takes your Flutter app’s request, validates the data format, and pushes it to Airtable correctly. You get logging and monitoring too, so when something breaks, you actually know why.

Used this approach for similar employee management systems. Takes about 10 minutes to set up the workflow, then your Flutter app just hits one clean endpoint. No more API debugging at 2 AM.