ai-ml

OpenTelemetry gen_ai Attributes: 60 Deprecated in 2026

September 24, 2026

OpenTelemetry gen_ai Attributes: 60 Deprecated in 2026

Every gen_ai.* attribute in @opentelemetry/semantic-conventions is deprecated as of v1.42.0. I audited all 60 constants across six releases: 8 are genuine renames, 2 were removed outright, and 50 kept their exact string value and merely changed which repository owns them.

TL;DR

The opentelemetry gen_ai attributes deprecated warnings landing in your editor are mostly noise, but not entirely.

On 2026-06-12, semantic-conventions v1.42.0 deprecated the whole GenAI namespace and moved it to a dedicated repository.1 The npm package followed on 2026-07-06.

I pulled six published versions of the package and counted the deprecation tags. The jump is abrupt: 10 deprecated constants at 1.41.1, then 60 at 1.42.0.

Only 10 of those 60 are a real problem. Eight attributes were renamed and two were deleted with no replacement. The other 50 emit the same string they always did.

The awkward part: as of 2026-09-24 there is no replacement package on npm or PyPI to migrate to. The deprecation tells you to go somewhere that has not shipped yet.

What you'll learn

  • Exactly what changed in semantic-conventions v1.42.0, quoted from the release notes
  • The measured deprecation count across six published npm releases
  • Which 8 gen_ai.* attributes were renamed, and which 2 were removed
  • Why the other 50 deprecations need no code change at all
  • That there is still no replacement package to import from
  • Why tsc --strict does not warn you about any of this
  • A script you can run to audit your own pinned version

What actually happened in v1.42.0

gen_ai semantic conventions moved out of OpenTelemetry's core repository into a dedicated GenAI repository, and everything left behind was marked deprecated. The v1.42.0 release notes list this under "Breaking changes."1

The release text is specific about the scope:

All gen_ai.* attributes, metrics, events, and spans previously defined under model/gen-ai/, model/openai/, and model/mcp/ (and documented under docs/gen-ai/) are deprecated in this repository and have moved to the OpenTelemetry GenAI semantic conventions repository.

Note model/mcp/ in that list. The Model Context Protocol conventions moved in the same commit, so MCP tool spans are part of the same migration as the agent that calls them.

The docs site agrees. Every page under /docs/specs/semconv/gen-ai/ now renders with the title "Moved: Generative AI semantic conventions" and a banner saying the page "is no longer maintained in this repository."2

The new repository describes itself as extending the core conventions with GenAI-specific ones, using Weaver to manage the dependency between them.3 Splitting a fast-moving area out of a repository with a strict stability bar is a defensible trade.

The cost is that the core package now ships 60 constants that all point somewhere else.

The measured deprecation count, release by release

I downloaded six published versions of @opentelemetry/semantic-conventions from npm, parsed build/src/experimental_attributes.d.ts, and counted JSDoc blocks carrying an @deprecated tag immediately above an exported gen_ai.* constant.

version   total  deprecated  live
1.34.0       38           6    32
1.37.0       42          10    32
1.40.0       56          10    46
1.41.1       60          10    50
1.42.0       60          60     0
1.43.0       60          60     0

Two things stand out.

The namespace grew fast and then stopped. It went from 38 attributes to 60 between 1.34.0 and 1.41.1, then flatlined — because after 1.42.0 new work happens in the other repository, not here.

And the deprecation is a cliff, not a slope. Ten constants were deprecated for several releases in the ordinary way. Then all 60 were deprecated in a single release.

Package publish dates from the npm registry, for the versions above: 1.40.0 on 2026-02-26, 1.41.1 on 2026-05-12, 1.42.0 on 2026-07-06, 1.43.0 on 2026-07-09. The npm latest tag is still 1.43.0, while the spec site's navigation already reads "Semantic conventions 1.44.0" — the JavaScript package lags the spec by a version.2

Which gen_ai attributes were actually renamed

Eight gen_ai.* attributes have a named replacement, so these are the ones that need a code change. The @deprecated tag on each constant states its replacement, which makes the list mechanical to extract rather than a judgement call:

Deprecated attributeReplacement
gen_ai.systemgen_ai.provider.name
gen_ai.usage.prompt_tokensgen_ai.usage.input_tokens
gen_ai.usage.completion_tokensgen_ai.usage.output_tokens
gen_ai.openai.request.response_formatgen_ai.output.type
gen_ai.openai.request.seedgen_ai.request.seed
gen_ai.openai.request.service_tieropenai.request.service_tier
gen_ai.openai.response.service_tieropenai.response.service_tier
gen_ai.openai.response.system_fingerprintopenai.response.system_fingerprint

The five OpenAI-specific rows share a pattern worth noticing. Three of them drop the gen_ai. prefix entirely and move to a top-level openai. namespace. A dashboard filtering on gen_ai.* will silently stop seeing those fields once an instrumentation library updates.

gen_ai.system to gen_ai.provider.name is the rename most likely to hurt, because gen_ai.system is the field you group by when you want cost or latency broken down per model vendor.

One caveat on all eight: the replacement constants are deprecated too. gen_ai.provider.name carries its own move notice in 1.43.0, as do gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. You are migrating to a name that is correct but no longer maintained in this package.

The 2 attributes removed with nothing to replace them

Two constants carry a different tag: "Removed, no replacement at this time."

  • gen_ai.prompt
  • gen_ai.completion

These were the flat, whole-blob prompt and completion fields. The conventions moved message capture to the structured gen_ai.input.messages and gen_ai.output.messages attributes, which first appeared in the package at 1.37.0 alongside gen_ai.provider.name and gen_ai.system_instructions.

Treat this as a removal, not a rename. The old attributes were single strings; the new ones are structured message lists, and content capture is opt-in. Copying a value across is not a migration.

Why 50 of the 60 deprecations need no code change

The remaining 50 attributes kept their exact string value; only the repository that defines them changed. Their @deprecated tag says nothing about a replacement — just "Moved to the OpenTelemetry GenAI semantic conventions repository."

That covers the entire agent vocabulary: gen_ai.agent.id, gen_ai.agent.name, gen_ai.agent.description, gen_ai.agent.version, gen_ai.conversation.id, gen_ai.tool.name, gen_ai.tool.call.id, gen_ai.tool.call.arguments, gen_ai.tool.call.result, gen_ai.tool.definitions, and the rest.

The arithmetic closes: 8 renamed + 2 removed + 50 moved = 60.

So if you are emitting gen_ai.agent.name today, the wire format does not change. Your backend queries keep matching. What you lose is a maintained constant to import, because the core package will not be the place those names live going forward.

Python is in the same position. The current PyPI release, opentelemetry-semantic-conventions 0.65b0, defines 52 gen_ai.* constants in _incubating/attributes/gen_ai_attributes.py, and all 52 carry a deprecation notice referencing the same move.

Is there a replacement package for the GenAI semantic conventions?

No — as of 2026-09-24 I could not find an OpenTelemetry-published GenAI semantic conventions package on either npm or PyPI. I checked six plausible npm names and two PyPI names; every one returned 404. Searching the npm registry for "semantic-conventions genai" returns only third-party packages.

The GenAI repository itself is active but unreleased: 601 commits, 136 open issues, 40 open pull requests, and an empty Releases section.3

This is not just a JavaScript gap. An issue on opentelemetry-rust puts it plainly:

there is currently no actionable path to follow through on (e.g. no new Rust crate that exposes the split out semantic conventions).

A maintainer replied, "I'll check and come back with a plan."4

There is a sharper version of this problem in the release notes themselves. v1.42.0 instructs: "Instrumentations following the new repository's conventions should refer to it for the corresponding schema_url to use."1 The new repository's README has a "Schema URL" section, and its body currently reads TODO.3

Are the OpenTelemetry GenAI semantic conventions stable?

No. Every gen_ai.* constant in the JavaScript package lives in experimental_attributes, reachable only through the /incubating entry point. The main package entry exports none of them.

I checked this on every version I pulled, from 1.27.0 through 1.43.0: not one gen_ai.* attribute has graduated to the stable set in any of them.

The practical consequence: a name can change in a minor release. gen_ai.system did exactly that.

Do deprecated gen_ai attributes still work?

Yes, and that is the trap — the deprecation does not fail your build. I installed @opentelemetry/semantic-conventions@1.43.0 with TypeScript 5.9.3, imported a deprecated constant, and compiled with strict: true and module: nodenext:

npx tsc -p .
# exit code 0, no diagnostics

The runtime values are untouched:

gen_ai.operation.name | gen_ai.agent.name

TypeScript surfaces @deprecated as an editor suggestion — a strikethrough in your IDE — not a compiler error. If nobody on the team opens that file, and your lint config has no deprecation rule, the whole migration is invisible to CI.

That is the argument for auditing deliberately rather than waiting for a build to complain.

Audit your own pinned version

This script takes a list of versions, packs each one from npm, and counts deprecated gen_ai.* constants. It produced the table earlier in this post.

// semconv-genai-audit.mjs
// Usage: node semconv-genai-audit.mjs 1.41.1 1.42.0 1.43.0
import { mkdtemp, readFile } from 'node:fs/promises';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

const run = promisify(execFile);
const versions = process.argv.slice(2);
const FILE = 'package/build/src/experimental_attributes.d.ts';
// one JSDoc block immediately followed by one exported gen_ai constant
const BLOCK =
  /\/\*\*((?:(?!\*\/)[\s\S])*?)\*\/\s*export declare const \w+:\s*"(gen_ai\.[^"]+)"/g;

console.log('version   total  deprecated  live');
for (const v of versions) {
  const dir = await mkdtemp(join(tmpdir(), 'semconv-'));
  await run('npm', ['pack', `@opentelemetry/semantic-conventions@${v}`, '--silent'], { cwd: dir });
  const [tgz] = (await run('ls', [dir])).stdout.trim().split('\n');
  await run('tar', ['xzf', join(dir, tgz), '-C', dir]);
  const src = await readFile(join(dir, FILE), 'utf8');

  let total = 0;
  let deprecated = 0;
  for (const [, doc] of src.matchAll(BLOCK)) {
    total++;
    if (/@deprecated/.test(doc)) deprecated++;
  }
  console.log(
    `${v.padEnd(9)} ${String(total).padStart(5)} ${String(deprecated).padStart(11)} ` +
      `${String(total - deprecated).padStart(5)}`
  );
}

A second pass groups the deprecations by reason, which is how the 8/2/50 split above was derived. Copy everything above the console.log('version ...') line from the first script, drop the loop, and append this:

// semconv-genai-reasons.mjs — reuses the imports, BLOCK regex and `src` from above
const renamed = [];
const removed = [];
const moved = [];

for (const [, doc, attr] of src.matchAll(BLOCK)) {
  const m = doc.match(/@deprecated\s+([^\n*]*)/);
  if (!m) continue;
  const reason = m[1].trim();
  const rename = reason.match(/^Replaced by `([^`]+)`/);

  if (/^Removed/.test(reason)) removed.push(attr);
  else if (rename) renamed.push([attr, rename[1]]);
  else moved.push(attr);
}

console.log(`renamed ${renamed.length}, removed ${removed.length}, moved ${moved.length}`);
for (const [from, to] of renamed) console.log(`  ${from}  ->  ${to}`);

Both scripts read only type declarations, so they need no API key and make no model calls. Run them against whatever version your lockfile actually pins.

Third-party conventions have drifted further than you think

While auditing, I checked what the vendor convention packages emit, and they are not converging on the OTel names.

@traceloop/ai-semantic-conventions 0.27.0 defines 15 gen_ai.* strings. None of the 15 appear in the OTel 1.43.0 registry.

Some are near-misses that will not match a query. It spells cache tokens gen_ai.usage.cache_creation_input_tokens, where OTel defines gen_ai.usage.cache_creation.input_tokens — underscores against a dot.

Its reasoning token field is gen_ai.usage.reasoning_tokens; OTel's is gen_ai.usage.reasoning.output_tokens. It also defines a nine-attribute gen_ai.guardrail.* namespace that OTel does not define at all.

The other two went further and did not use the namespace. @arizeai/openinference-semantic-conventions 2.12.0 and @langfuse/otel 5.11.1 emit zero gen_ai.* strings in their conventions packages, preferring their own vocabularies.

To be precise about scope: these are the vendors' convention packages, not every instrumentation package they ship. But the direction is clear enough. If you are normalising traces from more than one source, do not assume a shared vocabulary.

If you are still setting up agent tracing, the mechanics of emitting these spans are covered in trace Claude agent tool calls with OpenTelemetry.

The SDK-level exporter configuration is in Claude Agent SDK observability with OpenTelemetry, and the pipeline side — collector config and processors — in the OpenTelemetry Collector Node.js tracing tutorial.

What to do this week

Audit rather than react. Run the script against your pinned version and get a concrete list.

Fix the 10 that matter. Grep your instrumentation for the eight renamed names and the two removed ones. That is the entire code change.

Grep your dashboards and alert rules too, not just your source. The emitting side and the querying side drift independently, and a saved query filtering on gen_ai.system will quietly return nothing once a library updates.

Leave the other 50 alone. Changing a constant import for an attribute whose value did not change buys you nothing and risks a typo.

Do not go hunting for the new package. There isn't one yet on npm or PyPI. Pin your semconv version, keep the string literals you already emit, and revisit when the GenAI repository tags a release.

Bottom line

The headline — "all 60 gen_ai attributes deprecated" — sounds like a migration weekend. Measured, it is a ten-line change plus a dashboard grep.

The real cost is elsewhere. The conventions that agent observability depends on now live in a repository with no tagged release, no published package on npm or PyPI, and a TODO where its schema URL should be. The spec tells instrumentation authors to reference that schema URL.

Until that lands, the honest move is to pin your version, keep emitting the strings you already emit, and stop treating the strikethrough in your editor as a deadline.


Footnotes

  1. Release v1.42.0 · open-telemetry/semantic-conventions — released 12 June 2026, "Breaking changes" section. Fetched 2026-09-24. ↩ ↩2 ↩3 ↩4

  2. Moved: Generative AI semantic conventions — OpenTelemetry. Fetched 2026-09-24. ↩ ↩2

  3. open-telemetry/semantic-conventions-genai — repository README and metadata. Fetched 2026-09-24. ↩ ↩2 ↩3 ↩4

  4. Replacement for deprecated / moved gen_ai semantic conventions? · Issue #3575 · open-telemetry/opentelemetry-rust. Fetched 2026-09-24. ↩ ↩2

Frequently Asked Questions

Because semantic-conventions v1.42.0 (2026-06-12) moved the entire GenAI namespace — attributes, metrics, events and spans, plus the OpenAI and MCP conventions — into a dedicated repository so it could iterate faster than the core stability bar allows. The constants left behind in the core package were deprecated as part of that move. 1