passbolt/passbolt_api · error · BadRequestException
Subscription key data is required.
Error message
Subscription key data is required.
What it means
The controller requires a non-empty string in the 'data' form field containing the subscription key. When the field is missing, not a string, or whitespace-only, a 400 is thrown before any save attempt.
Solutions
- Send the subscription key as form field data=<key string>
- Ensure the key string is copied completely including BEGIN/END markers
- If sending JSON, use the expected form-encoded body the controller reads via getData('data')
- Verify the Content-Type is application/x-www-form-urlencoded (or multipart) so CakePHP parses the field
Example fix
// before curl -X POST .../subscription.jsonapi -H "Authorization: ..." # no body // after curl -X POST .../subscription.jsonapi -H "Authorization: ..." -d "data=-----BEGIN PGP MESSAGE----- ... -----END PGP MESSAGE-----"
Defensive patterns
Strategy: validation
Validate before calling
const key = subscriptionKey.trim();
if (!key) throw new Error('Subscription key data is required');
const body = new URLSearchParams({data: subscriptionKey});
// then send body as application/x-www-form-urlencoded Type guard
function hasSubscriptionKey(v) { return typeof v === 'string' && v.trim() !== ''; } Try / catch
if (res.status === 400 && body.message.includes('Subscription key data is required')) {
console.error('Send the key in the form field "data"');
} Prevention
- Always send the key under the exact form field name 'data'
- Use application/x-www-form-urlencoded (or multipart), not JSON
- Validate the key is non-empty before sending
When it happens
Trigger: POST /subscription.jsonapi without the data field, with data=, or with data=" "; sending JSON body instead of form data so getData('data') returns null.
Common situations: Scripts forgetting the -d "data=..." form field; copying an empty key from email; curl sending multipart without the field name matching exactly 'data'.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- An authentication token should be provided.
- Invalid request. New key is required for key rotation.
- Invalid request. Revoked key is required for key rotation.
- The expiry date is required.
- The request data is invalid: control_function missing.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/13cf2aafa68b2c13.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Subscription/src/Controller/Subscriptions/SubscriptionsUpdateController.php:43
use Passbolt\Subscription\Service\Subscriptions\SubscriptionKeySaveService;
/**
* Class SubscriptionsUpdateController
*/
class SubscriptionsUpdateController extends AppController
{
/**
* @return void
*/
public function update(): void
{
if (!$this->User->isAdmin()) {
throw new ForbiddenException(__('You are not allowed to access this location.'));
}
$keyString = $this->getRequest()->getData('data');
if (!is_string($keyString) || trim($keyString) === '') {
throw new BadRequestException(__('Subscription key data is required.'));
}
try {
$keyDto = (new SubscriptionKeySaveService())->save($keyString, $this->User->getAccessControl());
} catch (SubscriptionSignatureException $e) {
throw new BadRequestException($e->getMessage());
} catch (SubscriptionException $e) {
throw new PaymentRequiredException($e->getMessage(), $e->getErrors());
}
// POST and PUT both land here for backwards compatibility.
// Preserve the historical success messages of the now-deleted
// SubscriptionsCreateController (POST) and this controller (PUT) so the
// legacy SubscriptionsCreateControllerTest keeps passing unchanged.
$message = $this->getRequest()->is('post')
? __('The subscription was created.')
: __('The subscription was updated.');
View on GitHub (pinned to 31c1bbc10f)