{"record":{"id":"3bc5bfb0a8577d60","repo":"trailofbits/algo","slug":"no-private-key-provided","errorCode":null,"errorMessage":"No private key provided","messagePattern":"No private key provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"library/x25519_pubkey.py","lineNumber":83,"sourceCode":"                priv_b64 = stripped_data.decode()\n            except (base64.binascii.Error, ValueError):\n                # Second attempt: assume file contains raw binary data\n                # CRITICAL: Do NOT strip raw binary data - X25519 keys can contain\n                # whitespace-like bytes (0x09, 0x0A, etc.) that must be preserved\n                # Stripping would corrupt the key and cause \"got 31 bytes\" errors\n                if len(data) != 32:\n                    module.fail_json(\n                        msg=f\"Private key file must be either base64 or exactly 32 raw bytes, got {len(data)} bytes\"\n                    )\n                priv_b64 = base64.b64encode(data).decode()\n        except OSError as e:\n            module.fail_json(msg=f\"Failed to read private key file: {e}\")\n    else:\n        priv_b64 = module.params[\"private_key_b64\"]\n\n    # Validate input parameters\n    if not priv_b64:\n        module.fail_json(msg=\"No private key provided\")\n\n    try:\n        priv_raw = base64.b64decode(priv_b64, validate=True)\n    except Exception as e:\n        module.fail_json(msg=f\"Invalid base64 private key format: {e}\")\n\n    if len(priv_raw) != 32:\n        module.fail_json(msg=f\"Private key must decode to exactly 32 bytes, got {len(priv_raw)}\")\n\n    try:\n        priv_key = x25519.X25519PrivateKey.from_private_bytes(priv_raw)\n        pub_key = priv_key.public_key()\n        pub_raw = pub_key.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw)\n        pub_b64 = base64.b64encode(pub_raw).decode()\n        result[\"public_key\"] = pub_b64\n\n        if module.params[\"public_key_path\"]:\n            pub_path = module.params[\"public_key_path\"]","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/trailofbits/algo/blob/20e22a8715c198b38c01c1ca62d0953b93587a74/library/x25519_pubkey.py#L65-L101","documentation":"Neither private_key_path nor private_key_b64 yielded a key: the file branch was not taken (path not provided) and private_key_b64 is empty/None/falsy, so the module aborts before any cryptography work.","triggerScenarios":"Calling the module with neither argument, with private_key_b64: \"\" or a Jinja variable that rendered empty (undefined var defaulting to empty string).","commonSituations":"Jinja2 native mode returning empty strings for undefined variables, typo in the parameter name, or a preceding key-generation task skipped by a when condition.","solutions":["Pass exactly one of private_key_path or private_key_b64","Debug the variable feeding private_key_b64: add - debug: var=... to confirm it is non-empty","Use | default(..., true) if the source variable may be an empty string","Check the parameter spelling against the module's argument_spec"],"exampleFix":"# before\nprivate_key_b64: \"{{ user_key }}\"\n# after\nprivate_key_b64: \"{{ user_key | default('', true) }}{{ '' if not user_key else user_key }}\"  # or ensure user_key is set\n# better: assert the var first\n- assert:\n    that: user_key | default('', true) | length > 0","handlingStrategy":"validation","validationCode":"- assert:\n    that:\n      - (private_key_b64 | default('', true) | length) > 0 or (private_key_path | default('', true) | length) > 0","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always assert required key variables before the module task","Use default(..., true) so empty strings are treated as missing"],"tags":["x25519","missing-argument","ansible","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"20e22a8715c198b38c01c1ca62d0953b93587a74","analyzedAt":"2026-08-28T13:26:02.752Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}