run-llama/llama_index · error · ValueError

Cannot sign without private key

Error message

Cannot sign without private key

What it means

Raised by AgentMeshIdentity.sign in the llama-index-agent-agentmesh integration when the identity object has no private key. Identities can be created from public-key-only material (e.g. a remote peer's card) so you can verify signatures but not produce them; sign() guards against this empty private_key with a ValueError before attempting base64 decode and Ed25519 signing.

Source

Thrown at llama-index-integrations/agent/llama-index-agent-agentmesh/llama_index/agent/agentmesh/identity.py:92

        private_key_b64 = base64.b64encode(private_key_obj.private_bytes_raw()).decode(
            "ascii"
        )
        public_key_b64 = base64.b64encode(public_key_obj.public_bytes_raw()).decode(
            "ascii"
        )

        return cls(
            did=did,
            agent_name=agent_name,
            public_key=public_key_b64,
            private_key=private_key_b64,
            capabilities=capabilities or [],
        )

    def sign(self, data: str) -> CMVKSignature:
        """Sign data with this identity's private key."""
        if not self.private_key:
            raise ValueError("Cannot sign without private key")

        private_key_bytes = base64.b64decode(self.private_key)
        private_key_obj = ed25519.Ed25519PrivateKey.from_private_bytes(
            private_key_bytes
        )
        signature_bytes = private_key_obj.sign(data.encode("utf-8"))
        signature_b64 = base64.b64encode(signature_bytes).decode("ascii")

        return CMVKSignature(public_key=self.public_key, signature=signature_b64)

    def verify_signature(self, data: str, signature: CMVKSignature) -> bool:
        """Verify a signature against this identity's public key."""
        if signature.public_key != self.public_key:
            return False

        try:
            public_key_bytes = base64.b64decode(self.public_key)
            public_key_obj = ed25519.Ed25519PublicKey.from_public_bytes(

View on GitHub (pinned to afd0fef371)

Solutions

  1. Sign with an identity that was generated with a private key (use the identity-creation/generation path that produces both keys)
  2. Load the private key from your secret store and reconstruct the full identity before signing
  3. If you only need to verify a remote agent, call verify_signature instead of sign

Example fix

# before
peer = AgentMeshIdentity.from_agent_card(card)  # public-key only
sig = peer.sign(payload)  # ValueError: Cannot sign without private key

# after
me = AgentMeshIdentity.generate(agent_name="local-agent")  # has private key
sig = me.sign(payload)
ok = peer.verify_signature(payload, sig)
Defensive patterns

Strategy: type-guard

Validate before calling

def can_sign(identity) -> bool:
    return bool(getattr(identity, "private_key", None))

Type guard

from llama_index.agent.agentmesh.identity import AgentMeshIdentity

def is_signing_identity(id_: AgentMeshIdentity) -> bool:
    """True when the identity carries a private key and can produce signatures."""
    return isinstance(id_, AgentMeshIdentity) and bool(id_.private_key)

Try / catch

try:
    sig = identity.sign(payload)
except ValueError as e:
    if "Cannot sign" in str(e):
        raise PermissionError("use a local identity with a private key to sign") from e
    raise

Prevention

When it happens

Trigger: Calling identity.sign(data) on an AgentMeshIdentity constructed without a private key — e.g. one built from a received agent card containing only did/public_key/capabilities, or created with private_key=None/empty string. The falsy check on self.private_key fires before any crypto operations.

Common situations: Loading a peer agent's identity from its published card and then trying to sign a message with it; deserializing an identity where the private-key field was dropped (key stored in a secret manager not loaded in that env); mixing up local identity vs remote identity objects in mesh code.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/1c15840300949653. Report an issue: GitHub.