{"record":{"id":"38828e5b9f896bda","repo":"ellite/Wallos","slug":"the-label-is-not-set","errorCode":null,"errorMessage":"The label is not set.","messagePattern":"The label is not set\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"libs/OTPHP/OTP.php","lineNumber":102,"sourceCode":"        ] as $key => $default) {\n            if (isset($options[$key]) && $default === $options[$key]) {\n                unset($options[$key]);\n            }\n        }\n\n        ksort($options);\n    }\n\n    /**\n     * @param non-empty-string $type\n     * @param array<non-empty-string, mixed> $options\n     *\n     * @return non-empty-string\n     */\n    protected function generateURI(string $type, array $options): string\n    {\n        $label = $this->getLabel();\n        is_string($label) || throw new InvalidArgumentException('The label is not set.');\n        $this->hasColon($label) === false || throw new InvalidArgumentException('Label must not contain a colon.');\n        $options = [...$options, ...$this->getParameters()];\n        $this->filterOptions($options);\n        $params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options, '', '&'));\n\n        return sprintf(\n            'otpauth://%s/%s?%s',\n            $type,\n            rawurlencode(($this->getIssuer() !== null ? $this->getIssuer() . ':' : '') . $label),\n            $params\n        );\n    }\n\n    /**\n     * @param non-empty-string $safe\n     * @param non-empty-string $user\n     */\n    protected function compareOTP(string $safe, string $user): bool","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/ellite/Wallos/blob/52820e87ca5a6e105fdbb7f1c0c681bc0cfee2fd/libs/OTPHP/OTP.php#L84-L120","documentation":"OTP::generateURI (backing getProvisioningUri) requires a label; it throws InvalidArgumentException when getLabel() returns null. The otpauth URI scheme mandates otpauth://<type>/<label>, so a label must be set before a provisioning URI can be produced.","triggerScenarios":"Calling getProvisioningUri() on a TOTP/HOTP object created from a secret alone without calling setLabel(), e.g. TOTP::create($secret) then getProvisioningUri().","commonSituations":"Generating QR codes for authenticator apps before assigning an account label; refactors that dropped setLabel(); labels lost when objects were rebuilt from secrets stored in DB.","solutions":["Call setLabel() before getProvisioningUri(): $totp->setLabel('alice@example.com').","Include the label when creating: TOTP::create($secret, null, 'sha1', 6, 'alice@example.com').","If loading from a URI, ensure the path segment (label) is present.","Guard: if ($otp->getLabel() === null) { $otp->setLabel($defaultLabel); }"],"exampleFix":"// before\n$totp = TOTP::create($secret);\n$uri = $totp->getProvisioningUri(); // throws\n// after\n$totp = TOTP::create($secret);\n$totp->setLabel('alice@example.com');\n$uri = $totp->getProvisioningUri();","handlingStrategy":"validation","validationCode":"if ($otp->getLabel() === null) {\n    $otp->setLabel($user->email);\n}\n$uri = $otp->getProvisioningUri();","typeGuard":"function hasLabel(object $otp): bool {\n    return is_string($otp->getLabel()) && $otp->getLabel() !== '';\n}","tryCatchPattern":"try {\n    $uri = $otp->getProvisioningUri();\n} catch (InvalidArgumentException $e) {\n    $otp->setLabel('unknown-account');\n    $uri = $otp->getProvisioningUri();\n}","preventionTips":["Make setLabel() part of your OTP enrollment flow before QR generation","Store the label alongside the secret in your DB schema","Wrap URI generation in a helper that enforces label presence","Add a smoke test: create -> getProvisioningUri for every OTP type"],"tags":["php","otp","provisioning-uri","missing-value"],"backgroundTag":"missing-required-argument","analyzedSha":"52820e87ca5a6e105fdbb7f1c0c681bc0cfee2fd","analyzedAt":"2026-09-13T14:09:30.873Z","contentChangedAt":"2026-09-13T14:09:30.873Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}