{"record":{"id":"107f249700b3ba15","repo":"ellite/Wallos","slug":"invalid-algorithm-parameter","errorCode":null,"errorMessage":"Invalid \"algorithm\" parameter.","messagePattern":"Invalid \"algorithm\" parameter\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"libs/OTPHP/ParameterTrait.php","lineNumber":96,"sourceCode":"    }\n\n    public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void\n    {\n        $this->issuer_included_as_parameter = $issuer_included_as_parameter;\n    }\n\n    public function getDigits(): int\n    {\n        $value = $this->getParameter('digits');\n        (is_int($value) && $value > 0) || throw new InvalidArgumentException('Invalid \"digits\" parameter.');\n\n        return $value;\n    }\n\n    public function getDigest(): string\n    {\n        $value = $this->getParameter('algorithm');\n        (is_string($value) && $value !== '') || throw new InvalidArgumentException('Invalid \"algorithm\" parameter.');\n\n        return $value;\n    }\n\n    public function hasParameter(string $parameter): bool\n    {\n        return array_key_exists($parameter, $this->parameters);\n    }\n\n    public function getParameter(string $parameter): mixed\n    {\n        if ($this->hasParameter($parameter)) {\n            return $this->getParameters()[$parameter];\n        }\n\n        throw new InvalidArgumentException(sprintf('Parameter \"%s\" does not exist', $parameter));\n    }\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/ellite/Wallos/blob/52820e87ca5a6e105fdbb7f1c0c681bc0cfee2fd/libs/OTPHP/ParameterTrait.php#L78-L114","documentation":"OTP classes store the HMAC hash algorithm as a URI parameter. getDigest() reads the 'algorithm' parameter and throws this InvalidArgumentException when the stored value is missing, not a string, or an empty string, because a digest cannot be computed otherwise.","triggerScenarios":"Calling getDigest() (directly or indirectly via at()/verify()) on an OTP object whose 'algorithm' parameter was never set, was set to null, or was set to a non-string/empty value bypassing the parameter map validation.","commonSituations":"Constructing a TOTP/HOTP programmatically with setParameter('algorithm', null), loading a provisioning URI whose query string has an empty algorithm= value, or upgrading library versions where the algorithm was previously defaulted silently.","solutions":["Call setParameter('algorithm', 'sha1') (or sha256/sha512) on the OTP object before using it","If parsing a provisioning URI, ensure the otpauth:// URI contains a non-empty algorithm query parameter","Check the object's getParameters() output to confirm what 'algorithm' currently holds"],"exampleFix":"// before\n$totp->setParameter('algorithm', null);\necho $totp->getDigest();\n// after\n$totp->setParameter('algorithm', 'sha256');\necho $totp->getDigest();","handlingStrategy":"validation","validationCode":"$params = $otp->getParameters();\nif (!isset($params['algorithm']) || !is_string($params['algorithm']) || $params['algorithm'] === '') {\n    $otp->setParameter('algorithm', 'sha1');\n}","typeGuard":"function hasAlgorithm($otp): bool {\n    $v = $otp->getParameters()['algorithm'] ?? null;\n    return is_string($v) && $v !== '';\n}","tryCatchPattern":"try {\n    $digest = $otp->getDigest();\n} catch (\\InvalidArgumentException $e) {\n    $otp->setParameter('algorithm', 'sha1');\n    $digest = $otp->getDigest();\n}","preventionTips":["Always construct OTPs via factory methods (createFromSecret) that set defaults","Never assign algorithm via raw array writes; use setParameter","Check hash_algos() support for non-standard digests"],"tags":["php","otp","parameter-validation"],"backgroundTag":"invalid-argument-value","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"}