{"record":{"id":"09b765238e940451","repo":"badges/shields","slug":"fetch-function-not-implemented-for-this-constr","errorCode":null,"errorMessage":"fetch() function not implemented for ${this.constructor.name}","messagePattern":"fetch\\(\\) function not implemented for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"services/dynamic/json-path.js","lineNumber":34,"sourceCode":"export default superclass =>\n  class extends superclass {\n    static category = 'dynamic'\n    static defaultBadgeData = { label: 'custom badge' }\n\n    /**\n     * Request data from an upstream API, transform it to JSON and validate against a schema\n     *\n     * @param {object} attrs Refer to individual attrs\n     * @param {Joi} attrs.schema Joi schema to validate the response transformed to JSON\n     * @param {string} attrs.url URL to request\n     * @param {object} [attrs.httpErrors={}] Key-value map of status codes\n     *    and custom error messages e.g: `{ 404: 'package not found' }`.\n     *    This can be used to extend or override the\n     *    [default](https://github.com/badges/shields/blob/master/services/dynamic-common.js#L8)\n     * @returns {object} Parsed response\n     */\n    async fetch({ schema, url, httpErrors }) {\n      throw new Error(\n        `fetch() function not implemented for ${this.constructor.name}`,\n      )\n    }\n\n    async handle(namedParams, { url, query: pathExpression, prefix, suffix }) {\n      const data = await this.fetch({\n        schema: Joi.any(),\n        url,\n        httpErrors,\n      })\n\n      let values\n      try {\n        values = jp({ json: data, path: pathExpression, eval: false })\n      } catch (e) {\n        const { message } = e\n        if (\n          message.includes('prevented in JSONPath expression') ||","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/dynamic/json-path.js#L16-L52","documentation":"This is a guard method on a BaseJsonPathService-style class: the abstract fetch() must be overridden by a concrete service that actually performs the HTTP request and parses the JSON. Calling fetch() directly on the base class (or an instance that forgot to implement it) throws this Error, naming the class that lacks the implementation.","triggerScenarios":"Instantiating the base service class directly (e.g. in tests or custom code) and calling fetch() or handle() on it, instead of instantiating a subclass such as JsonPath that overrides fetch().","commonSituations":"Unit tests targeting the abstract base class; users wiring the service class into custom badge code and picking the wrong class; refactoring renamed the overriding fetch() so it no longer satisfies the contract.","solutions":["Use the concrete service class (e.g. JsonPath / the registered service) rather than the base class","Add a fetch() override in your subclass that performs the request (see services/dynamic-common.js default)","Restore the fetch() override if a refactor accidentally removed it"],"exampleFix":"// before\nclass MyService extends BaseJsonPathService {}\nnew MyService().fetch({ schema, url, httpErrors }) // throws\n// after\nclass MyService extends BaseJsonPathService {\n  async fetch({ schema, url, httpErrors }) {\n    return this._fetch({ schema, url, httpErrors })\n  }\n}","handlingStrategy":"type-guard","validationCode":"function isFetchable(ServiceClass) {\n  return typeof ServiceClass === 'function' &&\n    ServiceClass.prototype.fetch !== BaseJsonPathService.prototype.fetch\n}","typeGuard":"function canFetch(instance) {\n  return instance.fetch !== BaseJsonPathService.prototype.fetch\n}\n// instantiate only subclasses where canFetch(new Cls()) is true","tryCatchPattern":"try {\n  const data = await service.fetch({ schema, url, httpErrors })\n} catch (e) {\n  if (e.message.startsWith('fetch() function not implemented for')) {\n    throw new Error(`Use a concrete subclass, not ${service.constructor.name}`)\n  }\n  throw e\n}","preventionTips":["Never instantiate abstract base service classes directly; use the registered concrete service","When subclassing, always override fetch() (reuse services/dynamic-common.js default if suitable)","Add a smoke test that calls handle() on every concrete service to catch missing overrides"],"tags":["javascript","abstract-method","subclass","badge"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}