One of my Serverless functions works perfectly fine in production but not in development

Site Name: https://leaguetracker.netlify.app/

Issue: I have 6 serverless functions which all work perfectly fine in production. I have recently discovered that through installing netlify-cli I am able to run netlify dev which allows me to develop the app with use of my serverless functions…

It is worth noting the following
Base directory is client
Build command is npm run build
Publish directory is client/build

To run netlify dev I CD into the client folder then run it.
Everything now sits inside my client folder.

These are my redirects in a _redirects file which sit in client/build

/search  /.netlify/functions/search  200
/ranked  /.netlify/functions/ranked  200
/history  /.netlify/functions/history  200
/match  /.netlify/functions/match  200
/leaderboard  /.netlify/functions/leaderboard  200
/champion-mastery  /.netlify/functions/championMastery  200

My leaderboard function works perfectly fine when running netlify dev however, my search function throws a 500 error but I have no idea why this is only when running netlify dev as it works in production.

This is the leaderboard function that works everywhere

const axios = require("axios");

async function handler(event, context) {
  try {
    const region = event.path.replace("/.netlify/functions/leaderboard/", "");
    const leaderboardResponse = await axios.get(
      `https://${region}.api.riotgames.com/lol/league-exp/v4/entries/RANKED_SOLO_5x5/CHALLENGER/I?page=1`,
      {
        headers: {
          "X-Riot-Token": process.env.RIOT_API_KEY,
        },
      }
    );

    // Return the leaderboard data
    return {
      statusCode: 200,
      body: JSON.stringify(leaderboardResponse.data),
    };
  } catch (error) {
    console.error(error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "An error occurred" }),
    };
  }
}

module.exports = { handler };


This is the search function that works only in production

const axios = require("axios");

async function handler(event, context) {
  try {
    const region = event.path
      .replace("/.netlify/functions/search/", "")
      .split("/")[0];
    const summonerName = event.path
      .replace("/.netlify/functions/search/", "")
      .split("/")[1];

    // Make a request to the Riot Games API to fetch player data
    const summonerResponse = await axios.get(
      `https://${region}.api.riotgames.com/lol/summoner/v4/summoners/by-name/${encodeURIComponent(
        summonerName
      )}`,
      {
        headers: {
          "X-Riot-Token": process.env.RIOT_API_KEY,
        },
      }
    );

    return {
      statusCode: 200,
      body: JSON.stringify(summonerResponse.data),
    };
  } catch (error) {
    console.error(error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "An error occurred" }),
    };
  }
}

module.exports = { handler };


I am unable to check any other functions as the rest of them are triggered after the search…

Any idea why this might be the case?

Since you’re using try...catch, what does the error in the console say?

Hello @hrishikesh , the error is rather long but can be found below;
Again, this only happens if I use

netlify dev

In production, it works perfeclty fiine.
Also noting that one of my functions that works in dev and prod returns

Request from ::1: GET /.netlify/functions/leaderboard/EUW1
Response with status 200 in 518 ms.
Request from ::1: GET /.netlify/functions/leaderboard/EUW1
Response with status 200 in 303 ms.
Request from ::1: GET /.netlify/functions/search/EUW1/Goldiez%20Boi
AxiosError: Request failed with status code 404
    at settle (C:\Users\keepi\OneDrive\Documents\Projects\lol-stat-tracker\client\node_modules\axios\dist\node\axios.cjs:1909:12)
    at Unzip.handleStreamEnd (C:\Users\keepi\OneDrive\Documents\Projects\lol-stat-tracker\client\node_modules\axios\dist\node\axios.cjs:2989:11)
    at Unzip.emit (node:events:525:35)
    at Unzip.emit (node:domain:489:12)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_BAD_REQUEST',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [ 'xhr', 'http' ],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function], Blob: [class Blob] },
    validateStatus: [Function: validateStatus],
    headers: AxiosHeaders {
      Accept: 'application/json, text/plain, */*',
      'X-Riot-Token': 'RGAPI-b4924281-dd96-41b0-a97a-0aa477e135e5',
      'User-Agent': 'axios/1.4.0',
      'Accept-Encoding': 'gzip, compress, deflate, br'
    },
    method: 'get',
    url: 'https://EUW1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
    data: undefined
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      finish: [Function: requestOnFinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: false,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    strictContentLength: false,
    _contentLength: 0,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'euw1.api.riotgames.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 9,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'euw1.api.riotgames.com',
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: null,
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      write: [Function: writeAfterFIN],
      [Symbol(res)]: null,
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: 12534,
      [Symbol(kHandle)]: null,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 60,
      [Symbol(kBytesRead)]: 488,
      [Symbol(kBytesWritten)]: 288,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'GET /lol/summoner/v4/summoners/by-name/Goldiez%2520Boi HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'X-Riot-Token: RGAPI-b4924281-dd96-41b0-a97a-0aa477e135e5\r\n' +
      'User-Agent: axios/1.4.0\r\n' +
      'Accept-Encoding: gzip, compress, deflate, br\r\n' +
      'Host: euw1.api.riotgames.com\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: nop],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype] {},
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 0,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'GET',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    joinDuplicateHeaders: undefined,
    path: '/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      joinDuplicateHeaders: undefined,
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 404,
      statusMessage: 'Not Found',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 22,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'euw1.api.riotgames.com',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 0,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'x-riot-token': [Array],
      'user-agent': [Array],
      'accept-encoding': [Array],
      host: [Array]
    },
    [Symbol(errored)]: null,
    [Symbol(kUniqueHeaders)]: null
  },
  response: {
    status: 404,
    statusText: 'Not Found',
    headers: AxiosHeaders {
      date: 'Tue, 18 Jul 2023 11:36:04 GMT',
      'content-type': 'application/json;charset=utf-8',
      'transfer-encoding': 'chunked',
      connection: 'close',
      vary: 'Accept-Encoding',
      'x-app-rate-limit': '20:1,100:120',
      'x-app-rate-limit-count': '1:1,3:120',
      'x-method-rate-limit': '2000:60',
      'x-method-rate-limit-count': '1:60',
      'x-riot-edge-trace-id': '766d4067-1984-474f-a4f1-629b705335bb'
    },
    config: {
      transitional: [Object],
      adapter: [Array],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [AxiosHeaders],
      method: 'get',
      url: 'https://EUW1.api.riotgames.com/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
      data: undefined
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: true,
      socket: [TLSSocket],
      _header: 'GET /lol/summoner/v4/summoners/by-name/Goldiez%2520Boi HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'X-Riot-Token: RGAPI-b4924281-dd96-41b0-a97a-0aa477e135e5\r\n' +
        'User-Agent: axios/1.4.0\r\n' +
        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
        'Host: euw1.api.riotgames.com\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/lol/summoner/v4/summoners/by-name/Goldiez%2520Boi',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'euw1.api.riotgames.com',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kUniqueHeaders)]: null
    },
    data: { status: [Object] }
  }
}
Response with status 500 in 289 ms.

Hey @hrishikesh it looks like I have managed to fix it. The issue was related to how the summonerName is being passed in the URL. summonerName in the URL is double-encoded, resulting in %2520 instead of %20 which in the detailed error was throwing the 404 error.

I have updated my search function to the below which has fixed it.

const axios = require("axios");

async function handler(event, context) {
  try {
    const pathParts = event.path
      .replace("/.netlify/functions/search/", "")
      .split("/");
    const region = pathParts[0];
    const encodedSummonerName = pathParts[1];
    const summonerName = decodeURIComponent(encodedSummonerName);

    // Make a request to the Riot Games API to fetch player data
    const summonerResponse = await axios.get(
      `https://${region}.api.riotgames.com/lol/summoner/v4/summoners/by-name/${encodeURIComponent(
        summonerName
      )}`,
      {
        headers: {
          "X-Riot-Token": process.env.RIOT_API_KEY,
        },
      }
    );

    return {
      statusCode: 200,
      body: JSON.stringify(summonerResponse.data),
    };
  } catch (error) {
    console.error(error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "An error occurred" }),
    };
  }
}

module.exports = { handler };