We Shipped a Breaking Change on Purpose, and Our Own Docs Still Teach the Old Field Names
The documentation defect below is live, it is ours, and we found it while writing this page.
A version bump that is not cosmetic
The credential data model moved from one major version to the next, and among the changes were the field names describing when a credential is valid.
The older version used names borrowed from the language of documents: when it was issued, when it expires. The newer version uses names describing validity directly: valid from, valid until.
Renaming two fields is a breaking change, because every consumer reading the old names gets nothing from a credential carrying the new ones. No error, no warning. A missing value.
Why we took the break rather than straddling it
We could have emitted both sets and satisfied everyone. Several implementations did exactly that.
We did not, for two reasons.
The European framework points at the newer model. A credential carrying the old field names is a credential that fails the requirement we are building toward, and carrying both is a way of never quite committing.
And straddling hides the cost rather than removing it. Consumers built against deprecated names keep working, so nobody migrates, and the break arrives later with more code behind it. Taking a breaking change early is cheaper than taking it late, provided you tell people.
That last clause is where we failed.
The part we got wrong
Our own developer documentation still shows the old field names.
The page explaining credentials to a developer uses the deprecated names throughout and the current ones not at all. A developer following it writes code reading a field our software does not emit, and gets an undefined value from a perfectly valid credential.
That is worse than an out-of-date page. It is an instruction, on a live surface, that produces broken code and gives no signal about why.
We found this while writing this article, by checking our own documentation against the type definitions the packages actually publish. The types are correct. The documentation is not.
Why we are putting that on a marketing page
Because a documentation defect is exactly the kind of thing a vendor fixes quietly and never mentions, and the pattern of quiet fixes is what makes a project's public claims hard to trust.
A breaking change is only defensible if the migration path is visible. We took the break for a defensible reason and then left the most-read explanation of it pointing the wrong way, which converts a good decision into a bad developer experience.
Publishing that costs us something, and it is the only version that is consistent with the rest of this site.
What this means if you are integrating
Read the type definitions rather than the prose. Types are generated from what the code does; prose is generated from what somebody understood at the time.
That is general advice rather than an excuse. Where a vendor's documentation and types disagree, the types are the product, and a vendor whose two sources disagree has told you something about their release process, ours included.
What to ask any credential vendor
"Which version of the data model do you emit, and do you emit both?" Emitting both is a legitimate choice and it should be a stated one rather than an accident.
"Do your docs and your type definitions agree?" Ask them to check while you wait. For us, as of this page, they do not.
"What broke when you migrated, and how did you tell people?" A vendor who has never taken a breaking change in this area has probably not moved with the standard.
"Where is the field-name mapping between versions?" If it does not exist, every integrator rediscovers it.
Where this leaves a decision
If you are integrating today, use the current field names, take them from the published types, and treat that documentation page as wrong until it changes.
If you are evaluating how a vendor handles standards movement, the useful signal is not that our docs drifted, because most do. It is whether the drift is disclosed with the specific page named, which is what this paragraph is.
Keep reading
- The Credential Is the First Thing About Your Identity You Are Given Rather Than Registered In
- The Cheapest Data Protection Is Not Receiving the Data
- The Format We Actually Ship Leaves a Trace, and We Would Rather You Knew Which One
- The Model Has Three Roles and Only One of Them Has a Reason to Move First