Skip to content

Bug: csapiCollections (and 5 sibling collection getters) crash with TypeError when landing page omits 'data' rel link (e.g. OpenSensorHub) #188

@nsnarayanam

Description

@nsnarayanam

Summary

OgcApiEndpoint.csapiCollections crashes with TypeError: Cannot read properties of null (reading 'collections') when the endpoint's landing page does not advertise a link with rel: "data" (or its long-URI variant). Five sibling collection getters share the same bug pattern.

The crash is triggered by a real, conformant CSAPI server: the OpenSensorHub demo (http://45.55.99.236:8080/sensorhub/api) cited in PR #136's own validation list.

Reproduction

import { OgcApiEndpoint } from '@camptocamp/ogc-client';

const endpoint = new OgcApiEndpoint('http://45.55.99.236:8080/sensorhub/api');
console.log(await endpoint.hasConnectedSystems);  // true (correct)
console.log(await endpoint.csapiCollections);     // ❌ throws

Stack trace:

TypeError: Cannot read properties of null (reading 'collections')
    at parseCollections (dist/dist-node.js:2873:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)

Root cause

Two interacting issues:

1. csapiCollections doesn't null-check data (the immediate crash)

src/ogc-api/endpoint.ts:230-236:

get csapiCollections(): Promise<string[]> {
  return Promise.all([this.data, this.hasConnectedSystems])
    .then(([data, hasCSAPI]) => (hasCSAPI ? data : { collections: [] }))
    .then(parseCollections)   // ← parseCollections(null) throws
    ...

Compare to the sibling allCollections, which correctly null-checks before calling parseCollections:

return this.data.then((dataDocument) =>
  dataDocument ? parseCollections(dataDocument) : []
);

The same null-deref pattern is present in 5 other getters sharing the Promise.all([this.data, this.hasX]).then(...).then(parseCollections) shape:

Line Getter
187 recordCollections
198 featureCollections
206 edrCollections
244 vectorTileCollections
257 mapTileCollections

2. Why data is null here (separate concern, broader fix)

collectionsUrl only follows links with rel: "data" or http://www.opengis.net/def/rel/ogc/1.0/data. OpenSensorHub's landing page uses rel: "collections" instead:

{
  "rel": "collections",
  "title": "Collections available on this server",
  "href": "http://45.55.99.236:8080/sensorhub/api/collections",
  "type": "application/json"
}

So collectionsUrl resolves to null, data resolves to null, and every dependent getter then crashes.

OGC API Common Part 2 specifies data as the canonical rel — OpenSensorHub is technically out of spec — but rel: "collections" is widely seen in the wild, and after the immediate null-deref is fixed, the library still won't discover any collections from these servers. Worth considering whether collectionsUrl should additionally accept rel: "collections" for compatibility.

Proposed fix

Minimum (unblocks the crash, no behavior change)

Mirror the allCollections null-guard in all six affected getters. Single-token edit per getter:

-    .then(([data, hasCSAPI]) => (hasCSAPI ? data : { collections: [] }))
+    .then(([data, hasCSAPI]) => (hasCSAPI && data ? data : { collections: [] }))

I've applied this to csapiCollections locally and verified the OpenSensorHub case now returns { hasConnectedSystems: true, collections: [] } cleanly (instead of crashing). The same diff applied to the other 5 getters would make them robust by symmetry.

Recommended (also fixes the empty-collections downstream issue)

Additionally, accept rel: "collections" in collectionsUrl:

-    ['data', 'http://www.opengis.net/def/rel/ogc/1.0/data'],
+    ['data', 'http://www.opengis.net/def/rel/ogc/1.0/data', 'collections'],

This is a pragmatic compatibility win for OpenSensorHub-style servers; happy to defer to maintainers on whether this belongs here vs. being treated as a server-conformance issue.

Why this matters / context

I'm building a Python ADK agent (Google Gemini) that uses @camptocamp/ogc-client/csapi via a Node CLI subprocess to query CSAPI endpoints from natural language. This is the second consumer of the library beyond ogc-csapi-explorer, so the bug surfaced immediately when probing the public test servers cited in PR #136.

Cross-references:

Environment

  • Node v24.15.0, npm 11.12.1
  • Snapshot: OS4CSAPI/ogc-client-CSAPI_2 phase-7 branch
  • Built locally with npm run build
  • Probed against OpenSensorHub on 2026-05-03

Narasimha Sharma Narayanam (@nsnarayanam )

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions