Install of picroft image - stuck at please wait a moment

just installed picroft from offical image.

now stuck at the CLI expecting it to give me the reg code.

instead. it says Please wait a moment as I finish booting up…

Is something broken in the official image?

100% working rpi 3+ with 32 gb card .

shows running core 21.2.2

please help?

Hey there,

Can post the logs from /var/log/mycroft/?

That will tell us what’s actually gone wrong as it could be many things from this description.

Today I took a virgin image from my craft for the pie installed it on to a denticle raspberry pi 3+ units and they both fail the same exact way

The set up never gets to the point of where Mycroft says it’s ready to get commands and keeps saying that it’s waiting to complete

Can you please post your log files?

I don’t have any Picroft’s setup at the moment. We’re really focused on the Mark II right now. So I’m happy to take a quick look at the logs to suggest something, but we really can’t provide official support for DIY setups at the moment.

i will post logs tonight. so I am saying that 99% the picroft IMG is broken and all picroft systems in uise (like mine) are all broken w/o no change from the user.

i installed the latest rpi os onto my rpi 3b+.
then installed mc core to it.
then rebooted.

mycroft is still stuck at please wait… waited 10 minutes for it

skills log:

2022-11-10 19:38:09.086 | INFO | 827 | mycroft.messagebus.load_config:load_message_bus_config:33 | Loading message bus configs
2022-11-10 19:38:09.094 | ERROR | 827 | mycroft_bus_client.client.client | === ConnectionRefusedError(111, ‘Connection refused’) ===
Traceback (most recent call last):
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_app.py”, line 312, in run_forever
self.sock.connect(
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_core.py”, line 249, in connect
self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options),
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 130, in connect
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 208, in _open_socket
raise err
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 185, in _open_socket
sock.connect(address)
ConnectionRefusedError: [Errno 111] Connection refused
2022-11-10 19:38:09.100 | ERROR | 827 | mycroft_bus_client.client.client | Exception closing websocket: ConnectionRefusedError(111, ‘Connection refused’)
2022-11-10 19:38:09.101 | WARNING | 827 | mycroft_bus_client.client.client | Message Bus Client will reconnect in 5.0 seconds.
2022-11-10 19:38:14.113 | INFO | 827 | mycroft_bus_client.client.client | Connected
2022-11-10 19:38:14.118 | INFO | 827 | mycroft.util.process_utils:start_message_bus_client:155 | Connected to messagebus
2022-11-10 19:38:14.133 | INFO | 827 | mycroft.skills.msm_wrapper:create_msm:96 | Acquiring lock to instantiate MSM
2022-11-10 19:38:14.136 | INFO | 827 | msm.mycroft_skills_manager | building SkillEntry objects for all skills

here is enclosure log.

pi@raspberrypi:~/.config/mycroft/identity $ cat /var/log/mycroft/enclosure.log
2022-11-10 19:38:08.622 | INFO | 836 | main:create_enclosure:55 | Creating generic enclosure, platform=‘None’
2022-11-10 19:38:08.719 | INFO | 836 | mycroft.messagebus.load_config:load_message_bus_config:33 | Loading message bus configs
2022-11-10 19:38:08.749 | INFO | 836 | mycroft.client.enclosure.base:create_gui_service:473 | Starting message bus for GUI…
2022-11-10 19:38:08.825 | INFO | 836 | mycroft.client.enclosure.base:create_gui_service:483 | GUI Message bus started!
2022-11-10 19:38:08.829 | INFO | 836 | mycroft.enclosure.display_manager:init_display_manager_bus_connection:152 | Connecting display manager to messagebus
2022-11-10 19:38:08.841 | INFO | 836 | mycroft.messagebus.load_config:load_message_bus_config:33 | Loading message bus configs
2022-11-10 19:38:08.852 | ERROR | 836 | mycroft_bus_client.client.client | === ConnectionRefusedError(111, ‘Connection refused’) ===
Traceback (most recent call last):
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_app.py”, line 312, in run_forever
self.sock.connect(
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_core.py”, line 249, in connect
self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options),
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 130, in connect
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 208, in _open_socket
raise err
File “/home/pi/mycroft-core/.venv/lib/python3.9/site-packages/websocket/_http.py”, line 185, in _open_socket
sock.connect(address)
ConnectionRefusedError: [Errno 111] Connection refused
2022-11-10 19:38:08.890 | ERROR | 836 | mycroft_bus_client.client.client | Exception closing websocket: ConnectionRefusedError(111, ‘Connection refused’)
2022-11-10 19:38:08.891 | WARNING | 836 | mycroft_bus_client.client.client | Message Bus Client will reconnect in 5.0 seconds.
2022-11-10 19:38:12.055 | INFO | 836 | mycroft_bus_client.client.client | Connected
2022-11-10 19:38:12.062 | INFO | 836 | mycroft.util.process_utils:start_message_bus_client:155 | Connected to messagebus
2022-11-10 19:38:12.064 | INFO | 836 | main:on_ready:26 | Enclosure started!
2022-11-10 19:38:13.906 | INFO | 836 | mycroft_bus_client.client.client | Connected

and it never told me my pairing code…

soooooooooooooooo frustrated. How did MyCroft get so broken when I touched nothing !

I have installed new raspberry pi os onto my rpi and latest mycroft and it STILL fails the same way. tried it on another identical rpi unit and it too fails same way.

Hey, can you post the complete log files?

The ConnectionRefusedErrors that you see are saying that they can’t connect to the message bus, likely the bus is still starting up and you can see that the bus client then successfully connects in both cases.

i concur that the bus does start up and I can send messages to the buss. the issue is in the skills manager.

it hangs on line 190 of mycroft_skills_manager.py and that is what is causing the forever Please wait message.

See #aaa line 190
#aaa left off hangs here
remote_skills.append(
SkillEntry(name, skill_dir, url, sha, msm=self)
)


Copyright (c) 2018 Mycroft AI, Inc.

This file is part of Mycroft Skills Manager

(see GitHub - MatthewScholefield/mycroft-light: A reimplementation of mycroft-core using a cleaner modular architecture).

Licensed to the Apache Software Foundation (ASF) under one

or more contributor license agreements. See the NOTICE file

distributed with this work for additional information

regarding copyright ownership. The ASF licenses this file

to you under the Apache License, Version 2.0 (the

“License”); you may not use this file except in compliance

with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,

software distributed under the License is distributed on an

“AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

KIND, either express or implied. See the License for the

specific language governing permissions and limitations

under the License.

“”"Install, remove, update and track the skills on a device

MSM can be used on the command line but is also used by Mycroft core daemons.
“”"
import time
import logging
from functools import wraps
from glob import glob
from multiprocessing.pool import ThreadPool
from os import path
from typing import Dict, List

from msm import GitException
from msm.exceptions import (
AlreadyInstalled,
AlreadyRemoved,
MsmException,
MultipleSkillMatches,
RemoveException,
SkillNotFound
)
from msm.skill_entry import SkillEntry
from msm.skill_repo import SkillRepo
from msm.skill_state import (
initialize_skill_state,
get_skill_state,
write_device_skill_state,
load_device_skill_state,
device_skill_state_hash
)
from msm.util import cached_property, MsmProcessLock

LOG = logging.getLogger(name)

CURRENT_SKILLS_DATA_VERSION = 2
ONE_DAY = 86400

def save_device_skill_state(func):
“”"Decorator to overwrite the skills.json file when skill state changes.

The methods decorated with this function are executed in threads.  So,
this contains some funky logic to keep the threads from stepping on one
another.
"""
@wraps(func)
def func_wrapper(self, *args, **kwargs):
    will_save = False
    if not self.saving_handled:
        will_save = self.saving_handled = True
    try:
        ret = func(self, *args, **kwargs)
    finally:
        if will_save:
            self.write_device_skill_state()
        # Always restore saving_handled flag
        if will_save:
            self.saving_handled = False

    return ret

return func_wrapper

class MycroftSkillsManager(object):
SKILL_GROUPS = {‘default’, ‘mycroft_mark_1’, ‘picroft’, ‘kde’,
‘respeaker’, ‘mycroft_mark_2’, ‘mycroft_mark_2pi’}
DEFAULT_SKILLS_DIR = “/opt/mycroft/skills”

def __init__(self, platform='default', skills_dir=None, repo=None,
             versioned=True):
    self.platform = platform
    self.skills_dir = (
            path.expanduser(skills_dir or '') or self.DEFAULT_SKILLS_DIR
    )
    self.repo = repo or SkillRepo()
    self.versioned = versioned
    self.lock = MsmProcessLock()

    # Property placeholders
    self._all_skills = None
    self._default_skills = None
    self._local_skills = None
    self._device_skill_state = None

    self.saving_handled = False
    self.device_skill_state_hash = ''
    with self.lock:
        self._init_skills_data()

def clear_cache(self):
    """Completely clear the skills cache."""
    self._device_skill_state = None
    self._invalidate_skills_cache()

@cached_property(ttl=ONE_DAY)
def all_skills(self):
    """Getting a list of skills can take a while so cache it.

    The list method is called several times in this class and in core.
    Skill data on a device just doesn't change that frequently so
    getting a fresh list that many times does not make a lot of sense.
    The cache will expire every hour to pick up any changes in the
    mycroft-skills repo.

    Skill installs and updates will invalidate the cache, which will
    cause this property to refresh next time is is referenced.

    The list method can be called directly if a fresh skill list is needed.
    """
    if self._all_skills is None:
        self._all_skills = self._get_all_skills()

    return self._all_skills

def _get_all_skills(self):
    LOG.info('building SkillEntry objects for all skills')
    self._refresh_skill_repo()

    #aaa
    LOG.info( 'aaa1 got here' )

    remote_skills = self._get_remote_skills()

    #aaa
    LOG.info( 'aaa2 dont get here' )

    all_skills = self._merge_remote_with_local(remote_skills)

    return all_skills

def list(self):
    """Load a list of SkillEntry objects from both local and remote skills

    It is necessary to load both local and remote skills at
    the same time to correctly associate local skills with the name
    in the repo and remote skills with any custom path that they
    have been downloaded to.

    The return value of this function is cached in the all_skills property.
    Only call this method if you need a fresh version of the SkillEntry
    objects.
    """
    all_skills = self._get_all_skills()
    self._invalidate_skills_cache(new_value=all_skills)

    return all_skills

def _refresh_skill_repo(self):
    """Get the latest mycroft-skills repo code."""
    try:
        self.repo.update()
    except GitException as e:
        if not path.isdir(self.repo.path):
            raise
        LOG.warning('Failed to update repo: {}'.format(repr(e)))

def _get_remote_skills(self):
    """Build a dictionary of skills in mycroft-skills repo keyed by id"""
    remote_skills = []

    for name, _, url, sha in self.repo.get_skill_data():
        skill_dir = SkillEntry.create_path(self.skills_dir, url, name)
        sha = sha if self.versioned else ''
        
        #aaa
        LOG.info( 'aaa _get_remote_skills 1 got here' )

        #aaa left off hangs here
        remote_skills.append(
            SkillEntry(name, skill_dir, url, sha, msm=self)
        )

    #aaa
    LOG.info( 'aaa _get_remote_skills 2' )

    return {skill.id: skill for skill in remote_skills}

def _merge_remote_with_local(self, remote_skills):
    """Merge the skills found in the repo with those installed locally."""
    all_skills = []
    for skill_file in glob(path.join(self.skills_dir, '*', '__init__.py')):
        skill = SkillEntry.from_folder(path.dirname(skill_file), msm=self,
                                       use_cache=False)
        if skill.id in remote_skills:
            skill.attach(remote_skills.pop(skill.id))
        all_skills.append(skill)
    all_skills.extend(remote_skills.values())

    return all_skills

@property
def local_skills(self):
    """Property containing a dictionary of local skills keyed by name."""
    if self._local_skills is None:
        self._local_skills = {
            s.name: s for s in self.all_skills if s.is_local
        }

    return self._local_skills

@property
def default_skills(self):
    if self._default_skills is None:
        default_skill_groups = self.list_all_defaults()
        try:
            default_skill_group = default_skill_groups[self.platform]
        except KeyError:
            LOG.error(
                'No default skill list found for platform "{}".  '
                'Using base list.'.format(self.platform)
            )
            default_skill_group = default_skill_groups.get('default', [])
        self._default_skills = {s.name: s for s in default_skill_group}

    return self._default_skills

def list_all_defaults(self):  # type: () -> Dict[str, List[SkillEntry]]
    """Generate dictionary of default skills in all default skill groups"""
    all_skills = {skill.name: skill for skill in self.all_skills}
    default_skills = {group: [] for group in self.SKILL_GROUPS}

    for group_name, skill_names in self.repo.get_default_skill_names():
        group_skills = []
        for skill_name in skill_names:
            try:
                group_skills.append(all_skills[skill_name])
            except KeyError:
                LOG.warning('No such default skill: ' + skill_name)
        default_skills[group_name] = group_skills

    return default_skills

def _init_skills_data(self):
    """Initial load of the skill state that occurs upon instantiation.

    If the skills state was upgraded after it was loaded, write the
    updated skills state to disk.
    """
    try:
        del(self.device_skill_state['upgraded'])
    except KeyError:
        self.device_skill_state_hash = device_skill_state_hash(
            self.device_skill_state
        )
    else:
        self.write_device_skill_state()

@property
def device_skill_state(self):
    """Dictionary representing the state of skills on a device."""
    if self._device_skill_state is None:
        self._device_skill_state = load_device_skill_state()
        skills_data_version = self._device_skill_state.get('version', 0)
        if skills_data_version < CURRENT_SKILLS_DATA_VERSION:
            self._upgrade_skills_data()
        else:
            self._sync_device_skill_state()

    return self._device_skill_state

def _upgrade_skills_data(self):
    """Upgrade the contents of the device skills state if needed."""
    if self._device_skill_state.get('version', 0) == 0:
        self._upgrade_to_v1()
    if self._device_skill_state['version'] == 1:
        self._upgrade_to_v2()

def _upgrade_to_v1(self):
    """Upgrade the device skills state to version one."""
    self._device_skill_state.update(blacklist=[], version=1, skills=[])
    for skill in self.local_skills.values():
        skill_data = self._device_skill_state.get(skill.name, {})
        try:
            origin = skill_data['origin']
        except KeyError:
            origin = self._determine_skill_origin(skill)
        beta = skill_data.get('beta', False)
        skill_state = initialize_skill_state(
            skill.name,
            origin,
            beta,
            skill.skill_gid
        )
        skill_state['installed'] = skill_data.get('installed', 0)
        if isinstance(skill_state['installed'], bool):
            skill_state['installed'] = 0
        skill_state['updated'] = skill_data.get('updated', 0)
        self._device_skill_state['skills'].append(skill_state)
    self._device_skill_state.update(upgraded=True)

def _upgrade_to_v2(self):
    """Upgrade the device skills state to version 2.

    This adds the skill_gid field to skill entries.
    """
    self._update_skill_gid()
    self._device_skill_state.update(version=2, upgraded=True)

def _sync_device_skill_state(self):
    """Sync device's skill state with with actual skills on disk."""
    self._add_skills_to_state()
    self._remove_skills_from_state()
    self._update_skill_gid()

def _add_skills_to_state(self):
    """Add local skill to state if it is not already there."""
    skill_names = [s['name'] for s in self._device_skill_state['skills']]
    for skill in self.local_skills.values():
        if skill.name not in skill_names:
            origin = self._determine_skill_origin(skill)
            skill_state = initialize_skill_state(
                skill.name,
                origin,
                False,
                skill.skill_gid
            )
            self._device_skill_state['skills'].append(skill_state)

def _remove_skills_from_state(self):
    """Remove skills from state that no longer exist in the filesystem."""
    skills_to_remove = []
    for skill in self._device_skill_state['skills']:
        is_not_local = skill['name'] not in self.local_skills
        is_installed_state = skill['installation'] == 'installed'
        if is_not_local and is_installed_state:
            skills_to_remove.append(skill)

    for skill in skills_to_remove:
        self._device_skill_state['skills'].remove(skill)

def _update_skill_gid(self):
    for skill in self._device_skill_state['skills']:
        try:
            local_skill = self.local_skills[skill['name']]
        except KeyError:
            skill['skill_gid'] = ''
        else:
            skill['skill_gid'] = local_skill.skill_gid

def _determine_skill_origin(self, skill):
    if skill.name in self.default_skills:
        origin = 'default'
    elif skill.url:
        origin = 'cli'
    else:
        origin = 'non-msm'

    return origin

def write_device_skill_state(self, data=None):
    """Write device's skill state to disk if it has been modified."""
    data = data or self.device_skill_state
    if device_skill_state_hash(data) != self.device_skill_state_hash:
        write_device_skill_state(data)
        self.device_skill_state_hash = device_skill_state_hash(data)

@save_device_skill_state
def install(self, param, author=None, constraints=None, origin=''):
    """Install by url or name"""
    if isinstance(param, SkillEntry):
        skill = param
    else:
        skill = self.find_skill(param, author)
    skill_state = initialize_skill_state(
        skill.name,
        origin,
        skill.is_beta,
        skill.skill_gid
    )
    try:
        skill.install(constraints)
    except AlreadyInstalled:
        log_msg = 'Skill {} already installed - ignoring install request'
        LOG.info(log_msg.format(skill.name))
        skill_state = None
        raise
    except MsmException as e:
        skill_state.update(
            installation='failed',
            status='error',
            failure_message=str(e)
        )
        raise
    else:
        skill_state.update(
            installed=time.time(),
            installation='installed',
            status='active',
            beta=skill.is_beta
        )
    finally:
        # Store the entry in the list
        if skill_state is not None:
            self.device_skill_state['skills'].append(skill_state)
            self._invalidate_skills_cache()

@save_device_skill_state
def remove(self, param, author=None):
    """Remove by url or name"""
    if isinstance(param, SkillEntry):
        skill = param
    else:
        skill = self.find_skill(param, author)
    try:
        skill.remove()
    except AlreadyRemoved:
        LOG.info('Skill {} has already been removed'.format(skill.name))
        raise
    except RemoveException:
        LOG.exception('Failed to remove skill ' + skill.name)
        raise
    else:
        remaining_skills = []
        for skill_state in self.device_skill_state['skills']:
            if skill_state['name'] != skill.name:
                remaining_skills.append(skill_state)
        self.device_skill_state['skills'] = remaining_skills
        self._invalidate_skills_cache()

def update_all(self):
    def update_skill(skill):
        entry = get_skill_state(skill.name, self.device_skill_state)
        if entry:
            entry['beta'] = skill.is_beta
        if skill.update():
            self._invalidate_skills_cache()
            self._device_skill_state = None
            if entry:
                entry['updated'] = time.time()

    return self.apply(update_skill, self.local_skills.values())

@save_device_skill_state
def update(self, skill=None, author=None):
    """Update all downloaded skills or one specified skill."""
    if skill is None:
        return self.update_all()
    else:
        if isinstance(skill, str):
            skill = self.find_skill(skill, author)
        skill_state = get_skill_state(skill.name, self.device_skill_state)
        if skill_state:
            skill_state['beta'] = skill.is_beta
        if skill.update():
            # On successful update update the update value
            if skill_state:
                skill_state['updated'] = time.time()
                self._invalidate_skills_cache()

@save_device_skill_state
def apply(self, func, skills, max_threads=20):
    """Run a function on all skills in parallel"""

    def run_item(skill):
        try:
            func(skill)
            return True
        except MsmException as e:
            LOG.error('Error running {} on {}: {}'.format(
                func.__name__, skill.name, repr(e)
            ))
            return False
        except:
            LOG.exception('Error running {} on {}:'.format(
                func.__name__, skill.name
            ))

    with ThreadPool(max_threads) as tp:
        return tp.map(run_item, skills)

@save_device_skill_state
def install_defaults(self):
    """Installs the default skills, updates all others"""

    def install_or_update_skill(skill):
        if skill.is_local:
            self.update(skill)
        else:
            self.install(skill, origin='default')

    return self.apply(
        install_or_update_skill,
        self.default_skills.values()
    )

def _invalidate_skills_cache(self, new_value=None):
    """Reset the cached skill lists in case something changed.

    The cached_property decorator builds a _cache instance attribute
    storing a dictionary of cached values.  Deleting from this attribute
    invalidates the cache.
    """
    LOG.info('invalidating skills cache')
    if hasattr(self, '_cache') and 'all_skills' in self._cache:
        del self._cache['all_skills']
    self._all_skills = None if new_value is None else new_value
    self._local_skills = None
    self._default_skills = None

def find_skill(self, param, author=None, skills=None):
    # type: (str, str, List[SkillEntry]) -> SkillEntry
    """Find skill by name or url"""
    if param.startswith('https://') or param.startswith('http://'):
        repo_id = SkillEntry.extract_repo_id(param)
        for skill in self.all_skills:
            if skill.id == repo_id:
                return skill
        name = SkillEntry.extract_repo_name(param)
        skill_directory = SkillEntry.create_path(self.skills_dir, param)
        return SkillEntry(name, skill_directory, param, msm=self)
    else:
        skill_confs = {
            skill: skill.match(param, author)
            for skill in skills or self.all_skills
        }
        best_skill, score = max(skill_confs.items(), key=lambda x: x[1])
        LOG.info('Best match ({}): {} by {}'.format(
            round(score, 2), best_skill.name, best_skill.author)
        )
        if score < 0.3:
            raise SkillNotFound(param)
        low_bound = (score * 0.7) if score != 1.0 else 1.0

        close_skills = [
            skill for skill, conf in skill_confs.items()
            if conf >= low_bound and skill != best_skill
        ]
        if close_skills:
            raise MultipleSkillMatches([best_skill] + close_skills)
        return best_skill

I dont see how to attach a file to this message :frowning:

it crashes here - see line … argh

def _get_remote_skills(self):
    """Build a dictionary of skills in mycroft-skills repo keyed by id"""
    remote_skills = []

    for name, _, url, sha in self.repo.get_skill_data():
        skill_dir = SkillEntry.create_path(self.skills_dir, url, name)
        sha = sha if self.versioned else ''
        
        #aaa
        LOG.info( 'aaa _get_remote_skills 1' )

        #aaa left off hangs here argh
        se = SkillEntry(name, skill_dir, url, sha, msm=self )

        #aaa
        LOG.info( 'aaa _get_remote_skills 2' )

        remote_skills.append( se )

        #aaa
        LOG.info( 'aaa _get_remote_skills 3' )

    #end

Any ideas? I can send you my broken unit for you to keep and debug and you send me a new mark 1 or 2 to keep?

called with parms:
2022-11-11 15:43:44.377 | INFO | 11466 | msm.mycroft_skills_manager | aaa _get_remote_skills 1.a name: “fallback-unknown” skill_dir: “/opt/mycroft/skills/fallback-unknown.mycroftai” url: “GitHub - MycroftAI/fallback-unknown: Mycroft AI official Unknown Fallback Skill - used if no Intent is matched to an Utterance” sha: “05493156872d9affc98276b41fbc29398d3bc0df” self: “<msm.mycroft_skills_manager.MycroftSkillsManager object at 0x73a93a10>”

seems that the Pythin engine is crashing at instantiating the SkillEntry(name, skill_dir, url, sha, msm=self )

failing here in skill_entry.py

    if msm:
        u = url.lower()

        # aaa
        LOG.info ( 'aaa SkillEntry init 1.2.1 u= "' + u + '"' )
        #  aaa SkillEntry init 1.2.1 u= "https://github.com/mycroftai/fallback-unknown"
        
        self.meta_info = msm.repo.skills_meta_info.get(u, {})

        # aaa
        LOG.info ( 'aaa SkillEntry init 1.2' )

why is ‘u’ set to a html page?

You could try to update msm and restart.

pip freeze | grep msm
pip install -U msm

see deeper bug in skill_repo

def load_skills_data(branch, path):
try:
market_info_url = (MYCROFT_SKILLS_DATA + “/” + branch +
“/skill-metadata.json”)

    # aaa
    LOG.info ( 'aaa load_skills_data 1.0 "' + market_info_url + '"' )

    # hangs at this line
    info = requests.get(market_info_url).json()

is a code bug… why is the request not returning?
yet in browser I get the json
https://raw.githubusercontent.com/MycroftAI/mycroft-skills-data/21.02/skill-metadata.json

mem issue?

Any ideas? I can send you my broken unit for you to keep and debug and you send me a new mark 1 or 2 to keep?

I’m confused, do you have Mark 2 and you try to install Picroft on it or do you just have a RPi 4 and try to install Picroft on it?

rpi 3 and is bricked.

i am in CA usa. where are you? Can I call you?