slackhq/nebula · error

failed to open session on slot %d

Error message

failed to open session on slot %d

What it means

New() opened a read-write session on the selected slot but OpenWriteSession failed, so the module is destroyed and this message (without the underlying cause) is returned. The library throws it because writing/deriving operations require a session and the token refused to open one.

Source

Thrown at pkclient/pkclient_cgo.go:60

	// Try to open a session on the slot
	slotIdx := 0
	for i, slot := range slots {
		if slot.ID() == slotId {
			slotIdx = i
			break
		}
	}

	client := &PKClient{
		module: module,
		id:     []byte(id),
		label:  []byte(label),
	}

	client.session, err = slots[slotIdx].OpenWriteSession()
	if err != nil {
		module.Destroy()
		return nil, fmt.Errorf("failed to open session on slot %d", slotId)
	}

	if len(pin) != 0 {
		err = client.session.Login(pin)
		if err != nil {
			// ignore "already logged in"
			if !errors.Is(err, pkcs11.Error(256)) {
				_ = client.session.Close()
				return nil, fmt.Errorf("unable to login. error: %w", err)
			}
		}
	}

	// Make sure the hsm has a private key for deriving
	client.privKeyObj, err = client.findDeriveKey(client.id, client.label, true)
	if err != nil {
		_ = client.Close() //log out, close session, destroy module
		return nil, fmt.Errorf("failed to find private key for deriving: %w", err)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Verify slotId matches a token-present slot (pkcs11-tool --list-slots)
  2. Close other processes/sessions holding the HSM and retry
  3. Restart the HSM/middleware daemon (e.g. pcscd) if the token is wedged
  4. Check vendor max-session limits and free sessions
  5. Re-plug/reseat the token or reset it if the slot is unresponsive

Example fix

// before
pkcs11_slot: 5
// after (pick a slot with a token)
# pkcs11-tool --list-slots
pkcs11_slot: 0
Defensive patterns

Strategy: retry

Validate before calling

// pick a slot that actually has a token before New()
ctx := pkcs11.New(modulePath); ctx.Initialize()
slots, _ := ctx.GetSlotList(true)
for _, s := range slots {
    info, err := ctx.GetTokenInfo(s)
    if err == nil { fmt.Println(s, info.Label) } // choose one with a token
}

Try / catch

client, err := pkclient.New(hsmPath, slot, pin, id, label)
if err != nil && strings.Contains(err.Error(), "failed to open session") {
    time.Sleep(2 * time.Second) // let other holders release sessions, then retry
    return pkclient.New(hsmPath, slot, pin, id, label)
}

Prevention

When it happens

Trigger: Calling New() when slots[slotIdx].OpenWriteSession() errors: slot is busy/exclusive, token not present, serial sessions exhausted, or user PIN blocks write sessions.

Common situations: Another process holds the only session (HSM max-session limit); wrong slotId so the chosen slot has no token; HSM in a bad state requiring reinsertion; vendor middleware misconfigured.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/be3359f62f937dc4. Report an issue: GitHub.