Skip to content

Parser hard-fails on external $refs that bundle() already skipped as unresolvable #4084

Closed

Description

@j-westover

Description

Description

When $RefParser.bundle() cannot resolve an external $ref, it logs Skipping unresolvable $ref: … and continues — but the $ref string appears to remain in the bundled spec object. Later, @hey-api/shared's parser walks the full schema graph and hard-fails on that same ref:

Reference not found: http://redfish.dmtf.org/schemas/v1/Sensor.yaml#/components/schemas/Sensor_SensorLowerCriticalExcerpt

So bundle treats the ref as skippable, but parse treats it as fatal. Scoped generation (with parser.filters.operations.include) still works because the parser never reaches the affected schema subtree — which is why this only shows up on full / unfiltered generation.

Thanks again for the quick turnaround on #3412 / #3422 — sibling schema hoisting made a huge difference for the DMTF Redfish spec. This feels like a related follow-on on full generation rather than a regression in that fix.

Steps to Reproduce

  1. Point openapi-ts at the current DMTF Redfish OpenAPI document (Version 2026.1):

    https://github.com/DMTF/Redfish-Publications/blob/c3a8a4c26d92/openapi/openapi.yaml
    

    Or live:

    https://raw.githubusercontent.com/DMTF/Redfish-Publications/refs/heads/main/openapi/openapi.yaml
    
  2. Run full generation — no REDFISH_SCOPE, no parser.filters.operations.include:

    openapi-ts
  3. Observe console output during bundle:

    Skipping unresolvable $ref: http://redfish.dmtf.org/schemas/v1/Sensor.yaml#/components/schemas/Sensor_SensorLowerCriticalExcerpt
    
  4. Generation then fails during parse:

    Reference not found: http://redfish.dmtf.org/schemas/v1/Sensor.yaml#/components/schemas/Sensor_SensorLowerCriticalExcerpt
    

For comparison, the 2025.4 spec (commit 26c949654e3e, January 2026) completes full generation successfully on the same toolchain — no Sensor excerpt ref, no failure.

Example chain (Redfish 2026.1)

The dangling ref is a wrapper → versioned redirect inside Sensor.yaml:

# http://redfish.dmtf.org/schemas/v1/Sensor.yaml
Sensor_SensorLowerCriticalExcerpt:
  $ref: http://redfish.dmtf.org/schemas/v1/Sensor.v1_9_3.yaml#/components/schemas/Sensor_v1_9_3_SensorLowerCriticalExcerpt

bundle() fv

Reproducible example or configuration

Minimal config — full mode, no operation filter:

import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
  input:
    'https://raw.githubusercontent.com/DMTF/Redfish-Publications/refs/heads/main/openapi/openapi.yaml',
  output: { path: 'src/client.full' },
  plugins: [
    '@hey-api/client-axios',
    '@hey-api/sdk',
    { name: '@hey-api/typescript', enums: 'javascript' },
  ],
});

Run: openapi-ts (no REDFISH_SCOPE, no parser.filters.operations.include).

OpenAPI specification (optional)

System information (optional)

@hey-api/openapi-ts: 0.98.2
@hey-api/json-schema-ref-parser: 1.4.3
@hey-api/shared: 0.4.8
Node.js: 22.16.0. <-- note, currently a hard requirement for our project, a lower version than what is pinned for openapi-ts.

Activity

  1. pullfrog commented on Jun 17, 2026

    @pullfrog
    Contributor

    Fix implemented but push blocked by authentication error: remote: Invalid username or token. Password authentication is not supported for Git operations.

    The fix wraps all six context.resolveRef() calls across parseRef() in three parsers (2.0.x, 3.0.x, 3.1.x) with try/catch. When a $ref can't be resolved (external refs that $RefParser.bundle() already skipped), the parser now logs console.warn("Skipping unresolvable $ref: ...") and continues instead of hard-failing with "Reference not found".

    Changes

    • packages/shared/src/openApi/3.0.x/parser/schema.ts: parseRef() — wrapped both resolveRef calls in try/catch
    • packages/shared/src/openApi/3.1.x/parser/schema.ts: parseRef() — wrapped both resolveRef calls in try/catch
    • packages/shared/src/openApi/2.0.x/parser/schema.ts: parseRef() — wrapped both resolveRef calls in try/catch

    Verification

    • All 38 test files (526 tests) pass in @hey-api/shared ✅
    • Typechecking shows no new errors (pre-existing issues only) ✅
    • Self-review flagged 4 minor findings — all pre-existing patterns or out of scope, no blockers

    Commit is at b73aac0 on branch pullfrog/4084-handle-unresolvable-refs.

    Task list (8/8 completed)
    • Understand the issue: Parser hard-fails on external $refs that bundle() already skipped as unresolvable
    • Explore relevant code in @hey-api/shared parser and @hey-api/json-schema-ref-parser
    • Implement fix in 3.0.x parser: wrap resolveRef in try/catch in parseRef()
    • Implement fix in 3.1.x parser: wrap resolveRef in try/catch in parseRef()
    • Implement fix in 2.0.x parser: wrap resolveRef in try/catch in parseRef()
    • Build @hey-api/shared package
    • Run tests for @hey-api/shared
    • Push branch and create PR

    Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

  2. mrlubos commented on Jun 18, 2026

    @mrlubos
    Member

    @pullfrog try again

  3. pullfrog commented on Jun 18, 2026

    @pullfrog
    Contributor

    Created PR #4087: wrapped all six context.resolveRef() calls in parseRef() across the 2.0.x, 3.0.x, and 3.1.x parsers with try/catch. When a $ref can't be resolved (external refs that $RefParser.bundle() already skipped), the parser now logs console.warn("Skipping unresolvable $ref: ...") and continues instead of hard-failing. All 526 @hey-api/shared tests pass.

    Task list (8/8 completed)
    • Check existing branch and commit state for the fix
    • Read parseRef() in all three parsers
    • Wrap resolveRef() calls in try/catch in 3.0.x parser
    • Wrap resolveRef() calls in try/catch in 3.1.x parser
    • Wrap resolveRef() calls in try/catch in 2.0.x parser
    • Run tests for @hey-api/shared
    • Commit, push branch and create PR
    • Report progress

    Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

  4. mrlubos commented on Jun 18, 2026

    @mrlubos
    Member

    @j-westover try with the latest npm i @hey-api/openapi-ts@next, I made it delete those unresolvable references

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug 🔥Broken or incorrect behavior.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions