Unable to get local issuer certificate

We are building some serverless functions on netlify that work when deployed, but locally we have ‘unable to get local issuer certificate’ error. We are calling some google apis and other apis from these functions. If we have to setup proxy, there is not good documentation to do so. Can anyone please help? It’s stupid to deploy every time to check a small change :frowning:

Hi there, glad you found us :wave: before we can help you, we need a little more information on the issues you are facing. Can you please share:

  • the name of your build instance: “example-jones.netlify.com
  • what your optimal end result is
  • what you have already tried
  • any error messages you have received in your terminal window or in the developer console
  • https://payment-app-api.netlify.app
  • To be able to run the solution successfully locally without getting ‘unable to get local issuer certificate’ error
  • Tried to generate local certificate using openssl and see if locally we can make https calls
  • The call fails with the following message ‘unable to get local issuer certificate’

Simply put there is nowhere documented a standard process of running netlify functions locally with https, so we don’t get certificate issues.

Please share an example of what you’re doing. Are you making a HTTPS request inside a Netlify Function? Are you trying to run Netlify Functions locally over HTTPS? What is it that you’re trying? Better code reproductions and explanations will allow us to help you.

Hello @hrishikesh
As explained in the initial post we have some netlify functions that call google and some other external apis. When we test locally the request is placed as http, but when we place the request after deploying the app it is placed as https. That is why we guess we get certificate issue locally and not after deploying. Now assuming that setting up proxy would allow us make https calls locally would fix the issue we have asked the question on this forum. If there is another better way to get around our issue we would appreciate that solution instead. Is the issue clear or more details are required?

Sorry to say @MaharashtraMandalDen, but more details would be useful. For example, I don’t understand your situation here:

but…

If you’re requesting HTTP, why would you get an error that’s more concerned with HTTPS?

Which is why I requested some example of your setup. Some pieces of code to show how it’s implemented, or screenshots?

I’m using Google APIs in my projects and I’m doing all testing locally. The site is not deployed even once, so everything appears to work fine. Since this sounds something specific to your setup, I’m afraid, before you explain your setup, we can’t provide any useful responses.

For example, here’s my Google API request which works fine:

const axiosInstance = axios.create({
    baseURL: 'https://www.googleapis.com/calendar/v3/calendars',
    headers: {
      authorization: `Bearer ${request.gToken}`
    },
    params: {
      singleEvents: true,
      timeMax: endOfToday(),
      timeMin: startOfToday(),
      timeZone: 'UTC'
    }
  })
  Promise.all(['id1', 'id2'].map((calendarId, calendarIdIndex) => {
    return axiosInstance({
      url: `/${calendarId}/events`
    }).then((calendarEventListResponse : {
      data : {
        items : Array<{
          end : {
            date? : string
            dateTime? : string
          }
          id : string
          start : {
            date? : string
            dateTime? : string
          }
          summary : string
        }>
      }
    }) => {
      if (calendarIdIndex === 0) {
        return {
          schedule: calendarEventListResponse.data.items.map(calendarEvent => {
            return {
              end: subSeconds(parseISO(calendarEvent.end.dateTime as string), 1),
              id: calendarEvent.id,
              start: calendarEvent.start.dateTime,
              summary: calendarEvent.summary
            }
          })
        }
      } else {
        return {
          ooo: calendarEventListResponse.data.items.filter(calendarEvent => {
            return ['blah', 'blah']
          }).map(calendarEvent => {
            return {
              end: subSeconds(startOfDay(parseISO(calendarEvent.end.date as string)), 1),
              id: calendarEvent.id,
              start: startOfDay(parseISO(calendarEvent.start.date as string)),
              summary: calendarEvent.summary
            }
          })
        }
      }
    }, (calendarEventListError : AxiosError) => {
      throw new ApiError('Failed to fetch calendar event list from Google', calendarEventListError.response?.status)
    })
  })).then(calendarEventParsedList => {
    reply.send(calendarEventParsedList)
  })

Here is an example of one of our functions that fails locally:

export const handler = async (event) => {
    let responseOut ={statusCode: 500, body: JSON.stringify({ error: 'Call to getNewTransactId Failed!' })}
    try {
      if(event.queryStringParameters){ 
        const { GoogleSpreadsheet } = require('google-spreadsheet')
        const doc = new GoogleSpreadsheet(process.env.GOOGLE_SHEET_ID)
        await doc.useServiceAccountAuth({ 
          client_email: process.env.GOOGLE_CLIENT_EMAIL,
          private_key: process.env.GOOGLE_PRIVATE_KEY.split("\\n").join("\n")})
        await doc.loadInfo()

        const eId= event.queryStringParameters.eventId
        const sheet = doc.sheetsByTitle[eId]
        const rows = await sheet.getRows()
        let transactId = eId.concat('-',String(rows.length + 1).padStart(4, '0'))
        responseOut = {statusCode: 200, body: JSON.stringify({transactId: transactId})}
    }
    else{responseOut ={statusCode: 400, body:JSON.stringify({ error: 'Query params in getnewtransact is empty!' })}  }  
    } catch (error) {
      console.error('Error from getNewTransctId function!',error)
      responseOut ={statusCode: 500, body:JSON.stringify({ error: error.message })}  
    }
    console.log('RESPONSE TO SEND',responseOut)
return responseOut
}

And here is the error we see:

{"error":"request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate"}

Setting up the Edge Functions environment. This may take a couple of minutes. »   Error: request to https://dl.deno.land/release/v1.22.0/deno-x86_64-pc-windows-msvc.zip failed, reason: unable to get local issuer certificate
⠸ Setting up the Edge Functions environment. This may take a couple of minutes.◈ Rewrote URL to /.netlify/functions/getNewTransactId?eventId=DW2022
Request from ::1: GET /.netlify/functions/getNewTransactId?eventId=DW2022
Response with status 404 in 3 ms.
⠇ Setting up the Edge Functions environment. This may take a couple of minutes.◈ Rewrote URL to /.netlify/functions/getNewTransctId?eventId=DW2022
Request from ::1: GET /.netlify/functions/getNewTransctId?eventId=DW2022
⠙ Setting up the Edge Functions environment. This may take a couple of minutes.Error from getNewTransctId function! FetchError: request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate
    at ClientRequest.<anonymous> (C:\MyPlayground\payment-app-api\node_modules\google-spreadsheet\node_modules\node-fetch\lib\index.js:1491:11)
    at ClientRequest.emit (node:events:513:28)
    at ClientRequest.emit (node:domain:489:12)
    at TLSSocket.socketErrorListener (node:_http_client:481:9)
    at TLSSocket.emit (node:events:513:28)
    at TLSSocket.emit (node:domain:489:12)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  type: 'system',
  errno: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
  code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
  config: {
    method: 'POST',
    url: 'https://www.googleapis.com/oauth2/v4/token',
    data: {
      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      assertion: 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwYXltZW50cy1zZXJ2aWNlLWFjY291bnRAcGF5bWVudHMtMzY1MzA4LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3NwcmVhZHNoZWV0cyIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTY3MTIxODE4MCwiaWF0IjoxNjcxMjE0NTgwLCJzdWIiOm51bGx9.eeLnrUMdlJtRt7jH1S-TaLb3OXi0S8w_ZKm28y9AQPgl2I2Hs6P-ty5czYYbvmzai2wAk1i7t04Z31P5kae-8btAZkEXhb30gpleql3bung3Le4DfxDSS95Q5Nufphi6pVgrn1nx7dbQq-MqGhWQsjnStvxEeMTCd0NYUUcejerld8ihNf_B7MHY-_ar7Oe5Xd24R63aXcSK6Q49YxWNrMGY69VrKbUCcAjF0dZdNd0FRQ2Xpj6pIVTkbyBtapsBWcWYgxA51xqRKn9xKEuLXH02PY8E9weqVu47TYRVg9qU4_83eYfPYba5RXsSRsgsTavffd2NjooMaVgsPzHg5Q'
    },
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Accept: 'application/json'
    },
    responseType: 'json',
    paramsSerializer: [Function: paramsSerializer],
    body: 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwYXltZW50cy1zZXJ2aWNlLWFjY291bnRAcGF5bWVudHMtMzY1MzA4LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3NwcmVhZHNoZWV0cyIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTY3MTIxODE4MCwiaWF0IjoxNjcxMjE0NTgwLCJzdWIiOm51bGx9.eeLnrUMdlJtRt7jH1S-TaLb3OXi0S8w_ZKm28y9AQPgl2I2Hs6P-ty5czYYbvmzai2wAk1i7t04Z31P5kae-8btAZkEXhb30gpleql3bung3Le4DfxDSS95Q5Nufphi6pVgrn1nx7dbQq-MqGhWQsjnStvxEeMTCd0NYUUcejerld8ihNf_B7MHY-_ar7Oe5Xd24R63aXcSK6Q49YxWNrMGY69VrKbUCcAjF0dZdNd0FRQ2Xpj6pIVTkbyBtapsBWcWYgxA51xqRKn9xKEuLXH02PY8E9weqVu47TYRVg9qU4_83eYfPYba5RXsSRsgsTavffd2NjooMaVgsPzHg5Q',
    validateStatus: [Function: validateStatus]
  }
}
RESPONSE TO SEND {
  statusCode: 500,
  body: '{"error":"request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate"}'
}
Response with status 500 in 690 ms.

Just to confirm, have you set this:

npm config set strict-ssl false