{"record":{"id":"018b4fddfcc63030","repo":"passbolt/passbolt_api","slug":"subscription-key-data-is-required","errorCode":null,"errorMessage":"Subscription key data is required.","messagePattern":"Subscription key data is required\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php","lineNumber":45,"sourceCode":"use Passbolt\\Subscription\\Error\\Exception\\Subscriptions\\SubscriptionSignatureException;\n\n/**\n * The in-product upgrade entry point.\n */\nclass EditionSubscriptionsCreateController extends AppController\n{\n    use LocatorAwareTrait;\n\n    /**\n     * @return void\n     */\n    public function create(): void\n    {\n        $this->User->assertIsAdmin();\n\n        $keyString = $this->getRequest()->getData('data');\n        if (!is_string($keyString) || trim($keyString) === '') {\n            throw new BadRequestException(__('Subscription key data is required.'));\n        }\n\n        $this->assertNotAlreadyPro();\n\n        try {\n            $keyDto = (new EditionUpgradeService())->upgrade($keyString, $this->User->getAccessControl());\n        } catch (SubscriptionSignatureException $e) {\n            throw new BadRequestException($e->getMessage());\n        } catch (SubscriptionException $e) {\n            throw new PaymentRequiredException($e->getMessage(), $e->getErrors());\n        }\n\n        $this->success(__('The subscription was created.'), $keyDto->toArray());\n    }\n\n    /**\n     * Rejects with HTTP 409 if the instance is already on PRO or already has a\n     * persisted subscription row.","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php#L27-L63","documentation":"EditionSubscriptionsCreateController::create reads the subscription key from the request 'data' field. If the value is missing, not a string, or an empty/whitespace-only string, it throws BadRequestException. The endpoint requires the raw subscription key payload in the request body.","triggerScenarios":"POSTing to the edition subscription endpoint with no 'data' field, with a non-string value (array/null), or with an empty/whitespace string.","commonSituations":"Client sends JSON without the data key; form/multipart encoding where the key lands in the wrong field; copying a subscription key that was actually empty; API client sending nested payload in wrong location.","solutions":["Send the subscription key as a non-empty string in the request 'data' field","Check the request Content-Type and encoding so 'data' is parsed correctly","Trim and verify the key content before calling the API"],"exampleFix":"// before\nawait fetch('/edition/subscriptions', {method: 'POST', body: JSON.stringify({})});\n// after\nawait fetch('/edition/subscriptions', {method: 'POST', body: JSON.stringify({data: subscriptionKeyString})});","handlingStrategy":"validation","validationCode":"const data = payload.data;\nif (typeof data !== 'string' || data.trim() === '') {\n  throw new Error('Subscription key data is required.');\n}","typeGuard":"function hasKeyData(v: unknown): v is string { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n  await api.post('/edition/subscriptions', {data: key});\n} catch (e) {\n  if (e.status === 400) { /* fix request payload: data must be non-empty string */ }\n}","preventionTips":["Validate request payloads against an API schema before sending","Confirm the key string is non-empty after reading from file/env","Use correct Content-Type so 'data' is parsed server-side"],"tags":["http","bad-request","api"],"backgroundTag":"empty-required-field","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}