dagger/dagger · error

resolve ID input %q: empty session ID

Error message

resolve ID input %q: empty session ID

What it means

Handle-form IDs are resolved relative to the session that produced the underlying result: the resolver looks the result up in the per-session cache using clientMetadata.SessionID. If the metadata exists but the session ID is empty, the lookup is impossible, so the resolver rejects the ID with this error.

Source

Thrown at dagql/call_request_input.go:113

			}
			return &ResultCallRef{Call: frame}, nil
		}
		frame, err := resultCallFromRecipeIDInput(ctx, id, memo)
		if err != nil {
			return nil, err
		}
		memo[dig] = frame
		if frame == nil {
			return nil, nil
		}
		return &ResultCallRef{Call: frame}, nil
	}
	clientMetadata, err := engine.ClientMetadataFromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("resolve ID input %q: current client metadata: %w", idInputDebugString(id), err)
	}
	if clientMetadata.SessionID == "" {
		return nil, fmt.Errorf("resolve ID input %q: empty session ID", idInputDebugString(id))
	}
	cache, err := EngineCache(ctx)
	if err != nil {
		return nil, fmt.Errorf("resolve ID input %q: current dagql cache: %w", idInputDebugString(id), err)
	}
	ref, err := cache.resultCallRefByResultID(ctx, clientMetadata.SessionID, id.EngineResultID())
	if err != nil {
		return nil, fmt.Errorf("resolve ID input %q: %w", idInputDebugString(id), err)
	}
	return ref, nil
}

func resultCallFromRecipeIDInput(ctx context.Context, id *call.ID, memo recipeCallMemo) (*ResultCall, error) {
	if id == nil {
		return nil, nil
	}
	if id.IsHandle() {
		return nil, fmt.Errorf("handle-form IDs cannot be converted to inline recipe calls: %s", idInputDebugString(id))

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Connect through a properly established Dagger session so the request carries a non-empty session ID.
  2. If constructing client metadata manually, set SessionID to the request's actual session.
  3. Check middleware/interceptors for header stripping that removes the session ID before it reaches the engine.

Example fix

// before
md := &engine.ClientMetadata{ClientID: id}
// after
md := &engine.ClientMetadata{ClientID: id, SessionID: sessionID}
Defensive patterns

Strategy: validation

Validate before calling

md, err := engine.ClientMetadataFromContext(ctx)
if err == nil && md.SessionID == "" {
    return fmt.Errorf("session ID missing; connect via an established session")
}

Try / catch

// catch and diagnose the empty-session case
if _, err := resultCallRefFromIDInput(ctx, id, memo); err != nil {
    if strings.Contains(err.Error(), "empty session ID") {
        // reconnect with a session-scoped client
    }
}

Prevention

When it happens

Trigger: resultCallRefFromIDInput receives a handle-form ID while the ctx's client metadata has an empty SessionID — e.g. metadata constructed manually without a session ID, or a request path that clears/never assigns the session.

Common situations: Hand-built engine.ClientMetadata structs in tests or tools; proxy/interceptor layers that strip or replace request headers carrying the session ID; a client connecting without establishing a session (e.g. using a bare connection rather than a session-scoped one).

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/c8e7ae5f0e28bcae. Report an issue: GitHub.