How to fix messaging/invalid-payload: Malformed message payload in Firebase

FirebaseINTERMEDIATEMEDIUMUpdated Dec 15, 2025· 251 views

This Firebase Cloud Messaging error occurs when the message payload structure is invalid, contains incorrect JSON formatting, uses reserved keywords, or has incompatible field types. The error prevents message delivery until the payload structure is corrected.

Quick fix

Fixes messaging/invalid-payload: Malformed message payload

// Validate your message payload structure
const message = {
  token: registrationToken,
  notification: {
    title: 'Notification Title',
    body: 'Notification body text'
  },
  data: {
    key1: 'value1',
    key2: 'value2'
  }
};

// Test JSON serialization
try {
  const jsonString = JSON.stringify(message);
  const parsed = JSON.parse(jsonString);
  console.log('JSON is valid');
} catch (error) {
  console.error('Invalid JSON:', error.message);
}

// Common JSON errors to check:
// - Trailing commas in objects/arrays
// - Missing quotes around keys
// - Unclosed brackets or braces
// - Invalid escape sequences in strings
  1. Validate JSON structure and syntax
  2. Remove reserved keywords from data payload
  3. Ensure all data payload values are strings
  4. Verify platform-specific configurations
firebase — error
// Validate your message payload structure
const message = {
token: registrationToken,
notification: {
title: 'Notification Title',
body: 'Notification body text'
},
data: {
key1: 'value1',
key2: 'value2'
}
};
// Test JSON serialization
try {
const jsonString = JSON.stringify(message);
const parsed = JSON.parse(jsonString);
console.log('JSON is valid');
} catch (error) {
console.error('Invalid JSON:', error.message);
}
// Common JSON errors to check:
// - Trailing commas in objects/arrays
// - Missing quotes around keys
// - Unclosed brackets or braces
// - Invalid escape sequences in strings
messaging/invalid-payload: Malformed message payload

What this error means

The "messaging/invalid-payload" error in Firebase Cloud Messaging (FCM) indicates that the message payload sent to the FCM API is structurally invalid or contains malformed data. This error occurs during payload validation before any message processing begins. FCM requires messages to follow a specific JSON structure with defined field types, naming conventions, and content restrictions. When the payload violates these requirements, the API rejects the request immediately with this error. Common violations include invalid JSON syntax, using reserved keywords in data payloads, incorrect field types, or mixing incompatible message configurations. This error is distinct from "invalid-argument" errors which focus on parameter values. The invalid-payload error specifically addresses the structure, format, and composition of the message payload itself.

Typical symptoms

  • Push notifications fail to send with "invalid-payload" error message
  • HTTP 400 response from FCM API indicating payload malformation
  • Error appears in Firebase Admin SDK logs with payload validation failure
  • Messages fail validation before reaching any devices
  • Error message may include specific field names that are malformed
  • Notifications fail consistently when using certain payload configurations

Common causes

  1. Invalid JSON structure in message payload (syntax errors, unclosed brackets, trailing commas)
  2. Using reserved keywords in data payload ("from", "notification", "message_type", or "gcm"-prefixed keys)
  3. Incorrect data types for payload fields (e.g., objects instead of strings in data payload)
  4. Missing required fields in notification or platform-specific configurations
  5. Mixing incompatible message types (e.g., topic message with token field)
  6. Malformed platform-specific configurations (Android, iOS APNS, or Web Push)
  7. Invalid nested structures in data payload (non-string values in data fields)
  8. Payload contains null or undefined values in required fields

How to fix "messaging/invalid-payload: Malformed message payload"

1Validate JSON structure and syntax

Start by ensuring your message payload is valid JSON without syntax errors:

javascript
// Validate your message payload structure
const message = {
  token: registrationToken,
  notification: {
    title: 'Notification Title',
    body: 'Notification body text'
  },
  data: {
    key1: 'value1',
    key2: 'value2'
  }
};

// Test JSON serialization
try {
  const jsonString = JSON.stringify(message);
  const parsed = JSON.parse(jsonString);
  console.log('JSON is valid');
} catch (error) {
  console.error('Invalid JSON:', error.message);
}

// Common JSON errors to check:
// - Trailing commas in objects/arrays
// - Missing quotes around keys
// - Unclosed brackets or braces
// - Invalid escape sequences in strings

If using string templates or concatenation to build messages, use proper JSON serialization instead.

2Remove reserved keywords from data payload

Check that your data payload doesn't use any reserved keywords:

javascript
// Reserved keywords that CANNOT be used in data payload
const reservedKeywords = [
  'from',
  'notification',
  'message_type',
  'collapse_key'
];

// Keys starting with these prefixes are also forbidden
const forbiddenPrefixes = ['google.', 'gcm.', 'gcm.notification.'];

// Example of checking data payload
const dataPayload = {
  userId: '12345',           // OK
  customKey: 'customValue',  // OK
  // 'from': 'sender',       // FORBIDDEN - reserved keyword
  // 'gcm.notification.title': 'Title'  // FORBIDDEN - gcm prefix
};

// Validation function
function validateDataKeys(data) {
  const keys = Object.keys(data || {});

  for (const key of keys) {
    // Check reserved keywords
    if (reservedKeywords.includes(key)) {
      console.error(`Reserved keyword "${key}" found in data payload`);
      return false;
    }

    // Check forbidden prefixes
    for (const prefix of forbiddenPrefixes) {
      if (key.startsWith(prefix)) {
        console.error(`Forbidden key prefix "${prefix}" in key "${key}"`);
        return false;
      }
    }
  }

  return true;
}

// Use the validator
if (!validateDataKeys(message.data)) {
  console.error('Data payload contains reserved keywords');
}

Rename any conflicting keys to custom values (e.g., use "sender" instead of "from").

3Ensure all data payload values are strings

FCM requires all values in the data payload to be strings. Convert other types:

javascript
// INCORRECT - non-string values in data payload
const incorrectMessage = {
  token: registrationToken,
  data: {
    userId: 12345,              // Number - will cause error
    isActive: true,             // Boolean - will cause error
    metadata: { key: 'value' }, // Object - will cause error
    items: ['a', 'b', 'c']      // Array - will cause error
  }
};

// CORRECT - all values converted to strings
const correctMessage = {
  token: registrationToken,
  data: {
    userId: '12345',                          // String
    isActive: 'true',                         // String
    metadata: JSON.stringify({ key: 'value' }), // Serialized object
    items: JSON.stringify(['a', 'b', 'c'])    // Serialized array
  }
};

// Helper function to convert data payload
function stringifyDataPayload(data) {
  const stringified = {};

  for (const [key, value] of Object.entries(data)) {
    if (typeof value === 'string') {
      stringified[key] = value;
    } else if (value === null || value === undefined) {
      // Skip null/undefined values or convert to empty string
      stringified[key] = '';
    } else {
      // Convert objects, arrays, numbers, booleans to JSON strings
      stringified[key] = JSON.stringify(value);
    }
  }

  return stringified;
}

// Use the helper
message.data = stringifyDataPayload(message.data);

Remember: the notification payload can contain non-string values, but the data payload cannot.

4Verify platform-specific configurations

Check that Android, iOS, and Web configurations are properly formatted:

javascript
// Correct message with platform-specific configs
const message = {
  token: registrationToken,

  // Common notification (optional)
  notification: {
    title: 'Title',
    body: 'Body text'
  },

  // Android-specific configuration
  android: {
    priority: 'high',  // 'normal' or 'high'
    notification: {
      sound: 'default',
      color: '#ff0000',
      tag: 'notification-tag'
    },
    ttl: 3600  // Time to live in seconds (number, not string)
  },

  // iOS APNS configuration
  apns: {
    payload: {
      aps: {
        alert: {
          title: 'iOS Title',
          body: 'iOS Body'
        },
        sound: 'default',
        badge: 1  // Number, not string
      }
    },
    headers: {
      'apns-priority': '10'  // String value
    }
  },

  // Web Push configuration
  webpush: {
    notification: {
      title: 'Web Title',
      body: 'Web Body',
      icon: 'https://example.com/icon.png'
    },
    fcmOptions: {
      link: 'https://example.com'
    }
  }
};

// Common mistakes:
// - Using string values for numeric fields (ttl, badge)
// - Incorrect priority values (must be 'normal' or 'high' for Android)
// - Missing required nested structures (apns.payload.aps)
// - Invalid URL formats in webpush fields

Refer to the official FCM documentation for complete field specifications for each platform.

5Test with a minimal payload first

Create a minimal message to verify basic structure, then add complexity:

javascript
// Step 1: Test minimal notification-only message
const minimalMessage = {
  token: registrationToken,
  notification: {
    title: 'Test',
    body: 'Test message'
  }
};

try {
  await admin.messaging().send(minimalMessage);
  console.log('Minimal message sent successfully');
} catch (error) {
  console.error('Minimal message failed:', error.message);
  // If this fails, issue is with token or basic setup
}

// Step 2: Add data payload
const withData = {
  ...minimalMessage,
  data: {
    test: 'value'
  }
};

try {
  await admin.messaging().send(withData);
  console.log('Message with data sent successfully');
} catch (error) {
  console.error('Data payload caused error:', error.message);
  // Issue is in data payload structure
}

// Step 3: Add platform-specific configs incrementally
const withAndroid = {
  ...withData,
  android: {
    priority: 'high'
  }
};

// Continue adding configurations one at a time to isolate
// which part of the payload is causing the malformation error

This incremental approach helps identify exactly which part of your payload is malformed.

6Enable detailed error logging and validation

Use Firebase Admin SDK validation and logging to get specific error details:

javascript
// Enable debug logging for Firebase Admin SDK
process.env.DEBUG = 'firebase-admin:*';

// Use dry run mode to validate without sending
const message = {
  // your message configuration
};

try {
  // Dry run validates the message without actually sending it
  const response = await admin.messaging().send(message, true);
  console.log('Message validation passed:', response);
} catch (error) {
  console.error('Validation failed:', error.message);

  // Check error details
  if (error.errorInfo) {
    console.error('Error code:', error.errorInfo.code);
    console.error('Error message:', error.errorInfo.message);
  }

  // Log the full error object for debugging
  console.error('Full error:', JSON.stringify(error, null, 2));
}

// Additional validation: check payload size
const payloadSize = JSON.stringify(message).length;
console.log(`Payload size: ${payloadSize} bytes`);

if (payloadSize > 4096) {
  console.warn('Payload exceeds 4KB limit');
}

// Validate specific fields
if (message.data) {
  console.log('Data payload keys:', Object.keys(message.data));
  console.log('Data payload values types:',
    Object.entries(message.data).map(([k, v]) => `${k}: ${typeof v}`)
  );
}

The error message will often include the specific field or structure that is malformed.

Advanced notes

### Common Malformed Payload Scenarios

Reserved Word Conflicts:
The "notification" key is particularly problematic. Using it as a key in the data payload while also using the top-level notification field can cause conflicts:

javascript
// PROBLEMATIC
const message = {
  notification: { title: 'Hi' },  // Top-level notification
  data: {
    notification: 'custom value'   // Reserved - conflicts with top-level
  }
};

Type Coercion Issues:
JavaScript may automatically coerce types during object construction. Always explicitly convert to strings:

javascript
const data = {
  count: String(42),           // Explicit conversion
  timestamp: Date.now().toString(),  // Convert number to string
  isEnabled: Boolean(value) ? 'true' : 'false'  // Boolean to string
};

Platform-Specific Payload Differences:

1. Android: Supports both notification and data messages; data payload values must be strings
2. iOS APNS: Uses nested aps structure; some fields like badge must be numbers
3. Web Push: Requires URLs in specific fields; supports additional options like icon and image

### Payload Size Considerations

While the overall message size limit is 4096 bytes, different parts have different constraints:
- Data payload: All key-value pairs count toward the limit
- Notification payload: Title, body, and other fields have individual limits
- Platform configs: Each platform's configuration adds to total size

Monitor payload size when including:
- Large JSON objects in data fields
- Multiple platform-specific configurations
- Long URLs or base64-encoded images

### Migration from Legacy FCM

If migrating from the legacy FCM API to v1:
- Legacy API accepted some non-string values in data payload (v1 does not)
- Error messages are more specific in v1 API
- Field names may have changed (e.g., priority moved to Android config)
- Validation is stricter in v1 API

### Testing Across Platforms

Create platform-specific test messages to ensure compatibility:

javascript
// Test Android-only message
const androidMessage = {
  token: androidToken,
  android: {
    priority: 'high',
    data: { key: 'value' }
  }
};

// Test iOS-only message
const iosMessage = {
  token: iosToken,
  apns: {
    payload: {
      aps: { alert: { title: 'Test', body: 'Test' } }
    }
  }
};

Use platform-specific tokens to test each configuration independently.

### Debugging Tools

1. JSON validators: Use online JSON validators to check syntax
2. Firebase Console: Test messages from the console to verify server-side configuration
3. Admin SDK dry run: Always test with dry run before production deployment
4. Logging: Log the stringified message before sending to inspect exact structure
5. Unit tests: Create tests for message construction to catch payload errors early

Frequently asked questions

What does "messaging/invalid-payload: Malformed message payload" mean?
The "messaging/invalid-payload" error in Firebase Cloud Messaging (FCM) indicates that the message payload sent to the FCM API is structurally invalid or contains malformed data. This error occurs during payload validation before any message processing begins. FCM requires messages to follow a specific JSON structure with defined field types, naming conventions, and content restrictions.
How do I fix "messaging/invalid-payload: Malformed message payload"?
This Firebase Cloud Messaging error occurs when the message payload structure is invalid, contains incorrect JSON formatting, uses reserved keywords, or has incompatible field types. The error prevents message delivery until the payload structure is corrected.
What causes "messaging/invalid-payload: Malformed message payload"?
Invalid JSON structure in message payload (syntax errors, unclosed brackets, trailing commas) Using reserved keywords in data payload ("from", "notification", "message_type", or "gcm"-prefixed keys) Incorrect data types for payload fields (e.g., objects instead of strings in data payload)
Is the "messaging/invalid-payload: Malformed message payload" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading