trailofbits/algo · error

No private key provided

Error message

No private key provided

What it means

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.

Source

Thrown at library/x25519_pubkey.py:83

                priv_b64 = stripped_data.decode()
            except (base64.binascii.Error, ValueError):
                # Second attempt: assume file contains raw binary data
                # CRITICAL: Do NOT strip raw binary data - X25519 keys can contain
                # whitespace-like bytes (0x09, 0x0A, etc.) that must be preserved
                # Stripping would corrupt the key and cause "got 31 bytes" errors
                if len(data) != 32:
                    module.fail_json(
                        msg=f"Private key file must be either base64 or exactly 32 raw bytes, got {len(data)} bytes"
                    )
                priv_b64 = base64.b64encode(data).decode()
        except OSError as e:
            module.fail_json(msg=f"Failed to read private key file: {e}")
    else:
        priv_b64 = module.params["private_key_b64"]

    # Validate input parameters
    if not priv_b64:
        module.fail_json(msg="No private key provided")

    try:
        priv_raw = base64.b64decode(priv_b64, validate=True)
    except Exception as e:
        module.fail_json(msg=f"Invalid base64 private key format: {e}")

    if len(priv_raw) != 32:
        module.fail_json(msg=f"Private key must decode to exactly 32 bytes, got {len(priv_raw)}")

    try:
        priv_key = x25519.X25519PrivateKey.from_private_bytes(priv_raw)
        pub_key = priv_key.public_key()
        pub_raw = pub_key.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw)
        pub_b64 = base64.b64encode(pub_raw).decode()
        result["public_key"] = pub_b64

        if module.params["public_key_path"]:
            pub_path = module.params["public_key_path"]

View on GitHub (pinned to 20e22a8715)

Solutions

  1. Pass exactly one of private_key_path or private_key_b64
  2. Debug the variable feeding private_key_b64: add - debug: var=... to confirm it is non-empty
  3. Use | default(..., true) if the source variable may be an empty string
  4. Check the parameter spelling against the module's argument_spec

Example fix

# before
private_key_b64: "{{ user_key }}"
# after
private_key_b64: "{{ user_key | default('', true) }}{{ '' if not user_key else user_key }}"  # or ensure user_key is set
# better: assert the var first
- assert:
    that: user_key | default('', true) | length > 0
Defensive patterns

Strategy: validation

Validate before calling

- assert:
    that:
      - (private_key_b64 | default('', true) | length) > 0 or (private_key_path | default('', true) | length) > 0

Prevention

When it happens

Trigger: Calling the module with neither argument, with private_key_b64: "" or a Jinja variable that rendered empty (undefined var defaulting to empty string).

Common situations: 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.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of trailofbits/algo@20e22a8715 (2026-08-28). Data as JSON: /api/errors/3bc5bfb0a8577d60. Report an issue: GitHub.