Skip to content

Support errorMessage - #146

Merged
jdesrosiers merged 9 commits into
hyperjump-io:mainfrom
Ahmedmhmud:feat/support-errorMessage
Oct 19, 2026
Merged

jdesrosiers merged 9 commits into
hyperjump-io:mainfrom
Ahmedmhmud:feat/support-errorMessage

Conversation

@Ahmedmhmud

@Ahmedmhmud Ahmedmhmud commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary of changes

Added support for the errorMessage keyword in diagnostic messages.

  • When a subschema’s keyword fails validation and that subschema defines errorMessage, the diagnostic now shows the custom message instead of the default one.
  • Resolution works by taking the failing keyword’s schemaLocation, stepping back to its parent, and reading errorMessage directly via getSchema() + Browser.value().
  • Confirmed working through $ref, nested anyOf/oneOf alternatives, and cases with multiple schemaLocations per error.
  • formatError() (and the functions that build on it) were changed from synchronous to async, since the lookup requires getSchema(). Existing formatError unit tests were updated to await/.resolves accordingly but the behavior of course is unchanged.

Unlike defaultSnippets/markdownDescription, errorMessage is not registered in the vscode.ts, the lookup reads the raw schema value directly rather than going through the annotation/keyword-recognition system, so registration isn’t actually necessary for this feature. I chose not to add it, but wanted to flag in case we’d prefer it registered anyway for consistency with the other VS Code keywords.

Closes #134

@jdesrosiers jdesrosiers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using getSchema won't always work for a variety of reasons. Have another try at this. Below is the direction I have in mind.

  1. Match VS Code's semantics

VS Code only uses errorMessage for type, enum, and const errors. patternErrorMessage (with a fallback to errorMessage) is used only for pattern and format errors.

Right now errorMessage replaces every message coming from a subschema, so it can hide unrelated failures:

{
  "type": "string",
  "minLength": 5,
  "errorMessage": "Must be text"
}

With "abc", the user should see "Expected a string with at least 5 characters", not "Must be text" because minLength was what failed, not type.

  1. Register errorMessage and patternErrorMessage as vscode keywords

One of the reasons reading Browser.value(parentSchema).errorMessage isn't good enough is because it goes around the vocabulary system. We never rely on actual keyword names. It always has to be based on the keyword URI.

Each of these keywords also needs defineKeyword(id, { annotation: true }) from @hyperjump/json-schema-errors. Without it, @hyperjump/json-schema-errors throws an unsupported keyword error. Please add this for the existing two keywords as well.

  1. Get the message from the evaluation, not by re-fetching schemas

The current lookup has a few problems:

  • It calls getSchema again for every error and every schema location, on every validation. The schemas were already compiled.
  • It finds the parent schema by cutting the location at the last /. That doesn't work for boolean schemas or error-handler locations, and the empty catch hides those cases.
  • It makes formatError and everything that calls it async, just to look up a string.

The validator already has all of this while it runs. Use an EvaluationPlugin instead. I think a separate plugin from LspEvaluationPlugin makes sense this time. Only schema-validation diagnostics uses this, so the plugin belongs in src/features/diagnostics/. That keeps the feature removable as one unit.

  1. Values
  • Outside the VS Code dialect these are unknown keywords, so they can hold anything. ajv-errors schemas commonly use an object form, "errorMessage": { "type": "..." }, which would currently show up as [object Object]. Ignore values that are not string values.

@Ahmedmhmud

Copy link
Copy Markdown
Contributor Author

Totally makes sense
Sorry for the misunderstanding, I'll take another look on it.
Thanks!

@Ahmedmhmud
Ahmedmhmud force-pushed the feat/support-errorMessage branch from 6fed299 to 70d8dfa Compare October 17, 2026 12:25
Ahmedmhmud and others added 9 commits October 18, 2026 20:19
The plugin is only used by SchemaValidationDiagnosticsProvider, so it's
registered there instead of in build-server.ts. A from() helper replaces the
unchecked cast so a missing registration fails loudly. Also reverts the
unrelated forEach-to-for-loop rewrites.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The messages only apply to keywords in the same schema, so they aren't
annotations. Also drops the defineKeyword registrations, which aren't needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Messages were collected for every supported keyword by schema location
alone, so a schema's message was used to explain keywords that passed, such
as a type inside a not, and leaked to other locations the schema was
evaluated at. Messages are now collected when a keyword fails, keyed by
instance location and schema location. The message replaces the error's
whole explanation, and an error that combines keywords from more than one
schema shows each distinct message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These are the remaining keywords VS Code uses errorMessage for.
minContains and maxContains are evaluated by contains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A false schema fails at its own location rather than a keyword's and can't
have a message of its own, so it uses the errorMessage of the schema that
applied it, at the location it was applied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Groups the errorMessage tests in their own describe block and adds coverage
for keywords in referenced schemas, keywords VS Code doesn't use errorMessage
for, property name patterns, and dialects that include the vscode vocabulary.
Tests that duplicated others, or that described the old behavior, are dropped.
The enum, format, oneOf, and nested alternative tests are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jdesrosiers
jdesrosiers force-pushed the feat/support-errorMessage branch from 52766da to 7bddb90 Compare October 19, 2026 03:27
@jdesrosiers
jdesrosiers merged commit 1afb0b3 into hyperjump-io:main Oct 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support errorMessage VScode's custom keyword

2 participants