Skip to content

OpenApiVisitorBase PathString is not correct for v2 documents #2806

Description

Describe the bug
The OpenApiVisitorBase.PathString is documented as 'Pointer to source of validation error in document', but when used with OpenApiWalker and the built-in validation system, it does not produce correct pointers when the input document is in the v2 format. This is because the walker operates on the shared data model which mirrors the v3 structure - which has already been manipulated by the v2 reader.

OpenApi File To Reproduce

{
    "swagger": "2.0",
    "info": {
        "title": "Test API",
        "version": "1.0.0"
    },
    "paths": {
        "/items": {
            "get": {
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "name": null
                            }
                        }
                    }
                }
            }
        }
    }
}

Expected behavior
I'd expect a validation error with the pointer:
#/paths/~1items/get/responses/200/schema/properties/name

Instead, we see a validation error with the pointer:
#/paths/~1items/get/responses/200/content/application~1octet-stream/schema/name

This example actually has two separate bugs in one:

  • It looks like a v3 pointer - the 'content/application~1octet-stream' is not present in the document.
  • It is also missing 'properties' path segment due to a bug in the ValidateSchemaPropertyHasValue rule.

Additional context
Ideally it seems like we need the walker to 'undo' the changes that the v2 reader makes to the structure so it can track what the pointer in the underlying document actually is.

At minimum we should document that the PathString is a path to the internal document representation, and not the original document - but IMO it's more useful to have a path to the location in the input document.

Activity

  1. baywet commented on Apr 13, 2026

    @baywet
    Member

    Thank you for using the SDK and for reaching out.

    To follow up on our conversation, implicitly the path provided here will always be "of the latest specification object model" (for validation errors). That's a factor or a couple of things:

    • commitment to have the object model of the library reflect the latest version of the specification
    • no context of the document version once it's been deserialized or when it's not being serialized

    I don't think we'd be in a position to accept a pull request that changed that aspect because that'd be a large breaking change.

    However we can accept a pull request that'd add "translation" methods to better support scenarios like "I'm building an app/service that ingests descriptions, my customers may upload any version, and I want to perform extra validation while giving them paths that make sense in their documents".

    In this regard, we could add a couple of methods to help with this translation like this pseudo code.

    var options = new OpenApiReaderSettings
    {
      ValidationRules = [] //some rules
    };
    
    var (document, parsingDiagnostics) = OpenApiDocument.Parse("openapi.yaml", options);
    // case 1: no validation rules passed:
    // path on those errors are already representative of the document, because coming from parsing infra
    // case 2: validation rules passed
    // paths are a mixed bag, but can be differentiated by type assertion on OpenApiValidationError
    
    var validator = new OpenApiValidator();
    var walker = new OpenApiWalker(validator);
    walker.Walk(document);
    
    validator.Diagnostics;
    // accessed through a different property
    // the type should be OpenApiValidationError instead of OpenApiError
    
    // here the paths are not, because rely on object model which always reflects the latest spec OM
    
    var validationError = validator.Diagnostic.Errors[0];
    
    var myV2Path = validationError.GetVersionedPath(OpenApiSpecVersion.V2);
    // string? because some paths don't have equivalents in v2
    
    // calls under the hood
    OpenApiPathHelper.GetVersionedPath(validationError.Path, OpenApiSpecVersion.V2);
    
    
    // rough implementation
    public static readonly Dictionary<OpenAPISpecVersion, IOpenApiPathRepresentationPolicy[]> policies = [];
    
    public static string? GetVersionedPath(string path, OpenApiSpecVersion targetVersion)
    {
    	if (targetVersion == OpenApiSpecVersion.V3_2)
    	{
    		return path;
    	}
    	var applicablePolicies = policies[targetVersion];
    	foreach (var policy in applicablePolicies)
    	{
    		if (policy.IsMatch(path))
    		{
    			return policy.GetVersionedPath(path);
    		}
    	}
    	return null;
    
    }

    Is this something you'd like to submit a pull request for provided some guidance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions