Andrew,
I can tell from experience of having built 9 widget now that this error can appear for many reasons. First thing to check is the manifest.json and make sure that the elements that you have set to true in that file do really exist in your widgets folder structure. Contrary to what the custom widget development walk through says many of my widgets manifest.json look like this:
{
"name": "Share",
"2D": true,
"3D": true,
"platform": "HTML",
"version": "1.1.2",
"wabVersion": "1.1",
"author": "Esri & Robert Scheitlin",
"description": "Share this map by using facebook, twitter, Google+, email, link, or embed code.",
"copyright": "",
"license": "http://www.apache.org/licenses/LICENSE-2.0",
"properties": {
"inPanel": true,
"hasConfig": true
}
}
Notice the difference:
{
"name": "CustomWidgetTemplate",
"2D": true,
"3D": false,
"platform": "HTML",
"version": "1.2",
"wabVersion": "1.2",
"author": "Esri R&D Center Beijing",
"description": "This is the custom widget",
"copyright": "",
"license": "http://www.apache.org/licenses/LICENSE-2.0",
"properties": {
"inPanel":true,
"hasLocale": true,
"hasStyle":true,
"hasConfig":true,
"hasUIFile":true,
"hasSettingPage":true,
"hasSettingUIFile":true,
"hasSettingLocale":true,
"hasSettingStyle":true,
"IsController":false
}
}
Let the existance of your file in the predefined folder structure control whether you have a hasSettingLocale, etc, etc.
Another big gotcha is having a nls.sometext in your HTML template file and that string not actually existing in your strings.js
Hope this helps