Search code examples
javascriptazurebotframeworkbots

Microsoft Bot Framework - Error reading bot file, but all env variables are correct?


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// See https://github.com/microsoft/botbuilder-samples for a more comprehensive list of samples.

// Import required pckages
const env = require('dotenv').config({path: './.env'});

const path = require('path');
const restify = require('restify');

// Import required bot services. See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder');
// Import required bot configuration.
const { BotConfiguration } = require('botframework-config');

// This bot's main dialog.
const { BasicBot } = require('./bot');

// Read botFilePath and botFileSecret from .env file
// Note: Ensure you have a .env file and include botFilePath and botFileSecret.
const ENV_FILE = path.join(__dirname, '.env');


// Get the .bot file path
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
let botConfig;
try {
    // Read bot configuration from .bot file.
    botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
    console.error(typeof(process.env.botFileSecret));
    console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
    console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
    console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.`);
    console.error(`\n - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.\n\n`);
    process.exit();
}

// For local development configuration as defined in .bot file
const DEV_ENVIRONMENT = 'development';

// bot name as defined in .bot file or from runtime
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);

// Get bot endpoint configuration by service name
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);

// Create adapter. 
// See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
const adapter = new BotFrameworkAdapter({
    appId: endpointConfig.appId || process.env.microsoftAppID,
    appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
    openIdMetadata: process.env.BotOpenIdMetadata
});

// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
    // This check writes out errors to console log
    // NOTE: In production environment, you should consider logging this to Azure
    //       application insights.
    console.error(`\n [onTurnError]: ${ error }`);
    // Send a message to the user
    context.sendActivity(`Oops. Something went wrong!`);
};

// Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state store to persist the dialog and user state between messages.
// let conversationState, userState;

// For local development, in-memory storage is used.
// CAUTION: The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, anything stored in memory will be gone.
// const memoryStorage = new MemoryStorage();
// conversationState = new ConversationState(memoryStorage);
// userState = new UserState(memoryStorage);

// CAUTION: You must ensure your product environment has the NODE_ENV set
//          to use the Azure Blob storage or Azure Cosmos DB providers.
// const { BlobStorage } = require('botbuilder-azure');
// Storage configuration name or ID from .bot file
// const STORAGE_CONFIGURATION_ID = '<STORAGE-NAME-OR-ID-FROM-BOT-FILE>';
// // Default container name
// const DEFAULT_BOT_CONTAINER = 'botstate';
// // Get service configuration
// const blobStorageConfig = botConfig.findServiceByNameOrId(STORAGE_CONFIGURATION_ID);
// const blobStorage = new BlobStorage({
//     containerName: (blobStorageConfig.container || DEFAULT_BOT_CONTAINER),
//     storageAccountOrConnectionString: blobStorageConfig.connectionString,
// });
// conversationState = new ConversationState(blobStorage);
// userState = new UserState(blobStorage);

// Create the main dialog.
let bot;
try {
    bot = new BasicBot(botConfig);
} catch (err) {
    console.error(`[botInitializationError]: ${ err }`);
    process.exit();
}

// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
    console.log(`\n${ server.name } listening to ${ server.url }`);
    console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
    console.log(`\nTo talk to your bot, open basic-bot.bot file in the Emulator`);
});

// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
    // Route received a request to adapter for processing
    adapter.processActivity(req, res, async (turnContext) => {
        // route to bot activity handler.
        await bot.onTurn(turnContext);
    });
});

I'm using this code, which comes straight from the Microsoft Bot Framework tutorial. Every time I run npm start, I'm getting the error in the very first try/catch block ("Error reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.")

I've checked and the .env is returning the right variables - console.log(process.env.botFileSecret) in the try/catch block returns the secret, and same for the filePath. But botConfig comes back as undefined here. Any ideas? Thank you!


Solution

  • @KevinMuraney I'm not sure which tutorial precisely it is that you're following, however I can outline the steps I took that successfully runs a v4 Node Basic Bot created from Azure Portal.


    So at a glance it appears your index.js that you have closely resembles the one that gets created if you downloaded the Basic Bot template from the Azure Portal.

    Step 1: Download Node Basic Bot Template in ABS

    To download v4 Node Basic Bot Template:

    Azure Portal > "Create a resource" top right > "AI + Machine Learning" > "Web App Bot" > fill out fields with what services you want > "Create"

    This is actually the index.js that gets generated as of 10/10/18. It varies slightly from what you have:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    // See https://github.com/microsoft/botbuilder-samples for a more comprehensive list of samples.
    
    // Import required packages
    const path = require('path');
    const restify = require('restify');
    
    // Import required bot services. See https://aka.ms/bot-services to learn more about the different parts of a bot.
    const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder');
    // Import required bot configuration.
    const { BotConfiguration } = require('botframework-config');
    
    // This bot's main dialog.
    const { BasicBot } = require('./bot');
    
    // Read botFilePath and botFileSecret from .env file
    // Note: Ensure you have a .env file and include botFilePath and botFileSecret.
    const ENV_FILE = path.join(__dirname, '.env');
    const env = require('dotenv').config({ path: ENV_FILE });
    
    // Get the .bot file path
    // See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
    const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
    let botConfig;
    try {
        // Read bot configuration from .bot file.
        botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
    } catch (err) {
        console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
        console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
        console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.`);
        console.error(`\n - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.\n\n`);
        process.exit();
    }
    
    // For local development configuration as defined in .bot file
    const DEV_ENVIRONMENT = 'development';
    
    // bot name as defined in .bot file or from runtime
    const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
    
    // Get bot endpoint configuration by service name
    const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);
    
    // Create adapter. 
    // See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
    const adapter = new BotFrameworkAdapter({
        appId: endpointConfig.appId || process.env.microsoftAppID,
        appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
        openIdMetadata: process.env.BotOpenIdMetadata
    });
    
    // Catch-all for errors.
    adapter.onTurnError = async (context, error) => {
        // This check writes out errors to console log
        // NOTE: In production environment, you should consider logging this to Azure
        //       application insights.
        console.error(`\n [onTurnError]: ${ error }`);
        // Send a message to the user
        context.sendActivity(`Oops. Something went wrong!`);
    };
    
    // Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
    // A bot requires a state store to persist the dialog and user state between messages.
    // let conversationState, userState;
    
    // For local development, in-memory storage is used.
    // CAUTION: The Memory Storage used here is for local bot debugging only. When the bot
    // is restarted, anything stored in memory will be gone.
    // const memoryStorage = new MemoryStorage();
    // conversationState = new ConversationState(memoryStorage);
    // userState = new UserState(memoryStorage);
    
    // CAUTION: You must ensure your product environment has the NODE_ENV set
    //          to use the Azure Blob storage or Azure Cosmos DB providers.
    // const { BlobStorage } = require('botbuilder-azure');
    // Storage configuration name or ID from .bot file
    // const STORAGE_CONFIGURATION_ID = '<STORAGE-NAME-OR-ID-FROM-BOT-FILE>';
    // // Default container name
    // const DEFAULT_BOT_CONTAINER = 'botstate';
    // // Get service configuration
    // const blobStorageConfig = botConfig.findServiceByNameOrId(STORAGE_CONFIGURATION_ID);
    // const blobStorage = new BlobStorage({
    //     containerName: (blobStorageConfig.container || DEFAULT_BOT_CONTAINER),
    //     storageAccountOrConnectionString: blobStorageConfig.connectionString,
    // });
    // conversationState = new ConversationState(blobStorage);
    // userState = new UserState(blobStorage);
    
    // Create the main dialog.
    let bot;
    try {
        bot = new BasicBot(botConfig);
    } catch (err) {
        console.error(`[botInitializationError]: ${ err }`);
        process.exit();
    }
    
    // Create HTTP server
    let server = restify.createServer();
    server.listen(process.env.port || process.env.PORT || 3978, function() {
        console.log(`\n${ server.name } listening to ${ server.url }`);
        console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
        console.log(`\nTo talk to your bot, open basic-bot.bot file in the Emulator`);
    });
    
    // Listen for incoming activities and route them to your bot main dialog.
    server.post('/api/messages', (req, res) => {
        // Route received a request to adapter for processing
        adapter.processActivity(req, res, async (turnContext) => {
            // route to bot activity handler.
            await bot.onTurn(turnContext);
        });
    });
    


    Step 2: Create an .env file with botFilePath and botFileSecret

    botFilePath = ./YourNodeBasicBotFileTest.bot
    botFileSecret = lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxPimTg=
    

    You can find the values inside your bot that you just created in the Azure Portal enter image description here

    Note that I had created the file at a sibling level to the automatically created bot.js and index.js

    enter image description here


    Step 3: npm install

    Add packages with npm install. While you're at it, check to make sure that both your node and npm versions are up to date as some have actually reported issues with the framework when they were older versions.

    node -v
    v8.12.0
    
    npm -v
    6.4.1
    

    Step 4: npm run start

    You can now test in emulator and see things are up and running. Download the latest here.


    TL;DR

    Try updating "everything" and let us know if things work for you then