{"record":{"id":"561f13da759f8606","repo":"trailofbits/algo","slug":"failed-to-read-private-key-file-e","errorCode":null,"errorMessage":"Failed to read private key file: {e}","messagePattern":"Failed to read private key file: (.+?)","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"library/x25519_pubkey.py","lineNumber":77,"sourceCode":"                data = f.read()\n            try:\n                # First attempt: assume file contains base64 text data\n                # Strip whitespace from edges for text files (safe for base64 strings)\n                stripped_data = data.strip()\n                base64.b64decode(stripped_data, validate=True)\n                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()","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/trailofbits/algo/blob/20e22a8715c198b38c01c1ca62d0953b93587a74/library/x25519_pubkey.py#L59-L95","documentation":"The module could not read the file given as private_key_path: the OS raised OSError (file not found, permission denied, or an I/O error) during open()/read(). The exception text is embedded in the message.","triggerScenarios":"private_key_path points to a nonexistent path, a file the Ansible user cannot read (bad ownership/mode on configs/), or a directory/IS-A-FILE error.","commonSituations":"Running ansible as a different user than the one that generated keys, wrong relative path (resolved relative to the play, not the roles dir), or configs/ owned by root.","solutions":["Check the path exists: ls -l <private_key_path>","Fix ownership/permissions: sudo chown -R $USER configs/ && chmod 600 <keyfile>","Use an absolute path in the task","If generated in a previous task, verify the key-generation task actually ran and produced the file"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import os\np = '/path/to/priv.key'\nassert os.path.isfile(p) and os.access(p, os.R_OK), f'cannot read {p}'","typeGuard":"def readable_file(p: str) -> bool:\n    import os\n    return bool(p) and os.path.isfile(p) and os.access(p, os.R_OK)","tryCatchPattern":null,"preventionTips":["Use absolute paths in playbooks","Keep configs/ owned by the ansible user","Create key files with mode '0600'"],"tags":["x25519","file-io","permissions","ansible"],"backgroundTag":"file-read-permission-denied","analyzedSha":"20e22a8715c198b38c01c1ca62d0953b93587a74","analyzedAt":"2026-08-28T13:26:02.752Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}