> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# SpanComponents encoding error when attaching feedback spans

export const plans_0 = "Any"

export const deployments_0 = "Any"

export const data_plane_version_0 = undefined

export const use_case_0 = "Use case - Attaching user feedback spans to a generation span across request boundaries using span.export() when the 'SpanComponents string is not properly encoded' error appears"

<Note>
  **Applies to:**

  * Plan - {plans_0}
  * Deployment - {deployments_0}
  * {data_plane_version_0}
  * {use_case_0}
</Note>

## Summary

**Issue:** Calling `traced()` with a `parent` value from `span.export()` throws `SpanComponents string is not properly encoded. This library only supports encoding versions up to 3`, or feedback spans fail to attach to nested spans created by `wrapTraced()`.

**Cause:** The encoding version mismatch occurs when one endpoint uses `@braintrust/otel` or `BRAINTRUST_OTEL_COMPAT` (producing V4 `SpanComponents`) while the other uses the default V3 decoder; transport corruption or incorrect span targeting can also cause failures.

**Resolution:** Ensure consistent OTel compatibility settings across endpoints, preserve exported span strings exactly during transport, and call `span.export()` from the correct span's callback.

## Resolution steps

### If you see the SpanComponents encoding version error

#### Step 1: Check OTel compatibility settings

Verify whether either the generation endpoint or feedback endpoint imports `@braintrust/otel` or sets `BRAINTRUST_OTEL_COMPAT=true`. Both endpoints must use identical settings.

```ts theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
// If using OTel compatibility, both endpoints need this
import "@braintrust/otel";
```

#### Step 2: Align OTel initialization

If using OTel compatibility mode, ensure both endpoints initialize it before any Braintrust tracing code runs and use `@braintrust/otel` version 0.4.5 or later.

If not using OTel, remove any `@braintrust/otel` imports or `BRAINTRUST_OTEL_COMPAT` flags from all endpoints.

### If the exported span string passes through URLs

#### Step 1: Encode for URL transport

The string from `span.export()` contains characters like `+`, `/`, and `=` that must be preserved exactly. Use `encodeURIComponent` when passing via URLs.

```ts theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
// Sending
const encoded = encodeURIComponent(await span.export());

// Receiving
const spanId = decodeURIComponent(encodedParam);
```

JSON transport requires no additional encoding.

### If feedback isn't attaching to nested wrapTraced spans

#### Step 1: Understand currentSpan() behavior

`currentSpan()` inside a `wrapTraced` callback returns the span created by that specific wrapper, not any inner spans created by the wrapped function.

```ts theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
const wrappedGenerateFunction = wrapTraced(
  async () => {
    const results = await generateFunction(); // may create its own spans
    const spanId = await currentSpan().export(); // exports the wrapper's span, not generateFunction's spans
    return { result: results, spanId };
  },
  { name: "generation" }
);
```

#### Step 2: Export from the target span

To attach feedback to a span created inside `generateFunction()`, call `export()` from within that function's own `wrapTraced` callback, not from the outer wrapper.

#### Step 3: Use root span as alternative

If targeting nested spans proves difficult, export and use the root trace span instead:

```ts theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
// This works for any feedback that applies to the overall trace
const rootSpanId = await currentSpan().export(); // from outermost wrapper
```

### For multiple feedback submissions

Create one child feedback span per submission rather than overwriting the same span:

```ts theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
// Call once per feedback event with the same parent spanId
await traced(
  async (span) => {
    span.log({
      scores: { user_rating: score },
      comment: comment,
      metadata: { timestamp: new Date().toISOString() }
    });
  },
  { name: "user_feedback", parent: generationSpanId }
);
```
