Курс › Коли щось пішло не так
Довідник · 47 типових помилок із 10 місій

🆘 Коли щось пішло не так

Тут зібрані усі помилки, які розібрані в лабораторних, — щоб не шукати по сторінках. Кожен пункт живе у своїй ЛР; ця сторінка лише збирає їх докупи й дає пошук.
Якщо своєї помилки тут немає — це нормально: прочитай її текст повністю, останній рядок майже завжди містить підказку. І принеси її на заняття, вона тут з'явиться.

ЛР1 · Ізоляційна Капсула до місії →

permission denied while trying to connect to the Docker daemon socket

permission denied while trying to connect to the Docker daemon socket Твій користувач не в групі docker. У Codespaces такого не буває; на своїй машині — sudo usermod -aG docker $USER, а тоді вийди й зайди в систему знову (нова група застосовується лише до нового сеансу).

📡 С.І.Д.: «Диспетчер тебе не знає. Це не відмова — це формальність: назвися й повертайся».

Cannot connect to the Docker daemon at unix:///var/run/docker.sock

Cannot connect to the Docker daemon at unix:///var/run/docker.sock Демон не запущений. На Linux — sudo systemctl start docker; у Docker Desktop — запусти сам застосунок і дочекайся зеленого індикатора.

📡 С.І.Д.: «Місто спить. Диспетчера нема на посту — будити нема кого».

bash: ps: command not found

bash: ps: command not found (усередині капсули) Це не поломка, а нормальний стан: ubuntu:24.04 — мінімальний образ і ps у ньому немає. Саме тому в етапі 2 ми спершу ставимо procps. Якщо пропусти[[g:в|ла]] цей крок — поверніся до нього.

📡 С.І.Д.: «У капсулі немає нічого зайвого. Хочеш дивитися на процеси — принеси інструмент».

docker: Error response from daemon: Conflict. The container name "/devbox-…" is already in use

docker: Error response from daemon: Conflict. The container name "/devbox-…" is already in use Контейнер із таким іменем уже існує (найчастіше — з попередньої спроби). Прибери: docker rm -f devbox-<суфікс>. Саме цю ситуацію на рівні 3 і треба зробити неможливою — скрипт мусить бути ідемпотентним.

📡 С.І.Д.: «Одна брама, одне ім'я. Або прибирай стару капсулу, або назви нову інакше».

echo $$ показує не 1, а щось на кшталт 4213

echo $$ показує не 1, а щось на кшталт 4213 Ти виконав команду не в капсулі, а на хості — термінал не той. Подивись на запрошення рядка: усередині капсули воно на кшталт root@a1b2c3…:/#, а не твоє звичайне.

📡 С.І.Д.: «Ти питаєш місто, а не капсулу. Різні співрозмовники — різні відповіді».

Якщо помилка не з цього списку — шукай точний текст у «Коли щось пішло не так», там зібрані всі помилки курсу.

ЛР2 · Кібер-Дієта до місії →

docker build падає з exec /sid: no such file or directory

docker build падає з exec /sid: no such file or directory — а файл же скопійований! Класика scratch: бінарник динамічно злінкований і шукає /lib64/ld-linux-x86-64.so.2, якого в порожньому образі немає. Збирай статично: Rust — --target x86_64-unknown-linux-musl (спершу rustup target add), Go — CGO_ENABLED=0.

📡 С.І.Д.: «Ти взя[[g:в|ла]] мене в дорогу без ніг. Файл на місці, а спертися ні на що».

Кеш не спрацьовує: кожна збірка йде з нуля, хоча код не змінювався

Кеш не спрацьовує: кожна збірка йде з нуля, хоча код не змінювався Ти скопіюва[[g:в|ла]] весь каталог (COPY . .) до встановлення залежностей — і будь-яка зміна в будь-якому файлі ламає кеш із цього місця й далі. Спершу копіюй тільки манифест (Cargo.toml), потім став залежності, і лише потім — код.

📡 С.І.Д.: «Ти щоразу перебудовуєш майстерню, щоб забити один цвях».

Фінальний образ важить майже як наївний

Фінальний образ важить майже як наївний Найчастіше — забутий AS build або COPY --from не з того етапу: тулчейн просто переїхав у фінальний образ разом із результатом. Перевір docker history lab02-slim — важкі шари видно одразу.

📡 С.І.Д.: «Ти зібра[[g:в|ла]] мене в новий костюм і взя[[g:в|ла]] з собою всю кравецьку».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР3 · Сліпий Канал до місії →

curl: (6) Could not resolve host: storage

curl: (6) Could not resolve host: storage Контейнери не в одній user-defined мережі. У стандартному bridge вбудованого DNS немає — імена там не резолвяться взагалі. Перевір docker inspect agent | grep -i network і при потребі під'єднай: docker network connect mission-net agent.

📡 С.І.Д.: «Листоноша не знає такої вулиці. Ти поклика[[g:в|ла]] його не в той квартал».

docker network create mission-net → network with name mission-net already exists

docker network create mission-net → network with name mission-net already exists Мережа лишилася з попередньої спроби. Це нормально: docker network rm mission-net або просто користуйся наявною.

📡 С.І.Д.: «Квартал уже змурований. Двічі мурувати не треба».

readlink /proc/<pid>/ns/net → Permission denied

readlink /proc/<pid>/ns/net → Permission denied Читання чужих просторів імен потребує прав: sudo readlink …. У Codespaces sudo доступний без пароля.

📡 С.І.Д.: «Ти дивишся у вічко чужих дверей. Вартові просять показати перепустку».

Секрет усе одно видно в docker inspect

Секрет усе одно видно в docker inspect Значення, передане через -e KEY=value, назавжди лишається в метаданих контейнера — його видно і в docker inspect, і в історії команд оболонки. Саме тому рівень 3 вимагає файлу, а не прапорця.

📡 С.І.Д.: «Ти написа[[g:в|ла]] ключ на конверті. Листоноша чесний, але конверт читають усі».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР4 · Кування Відмички до місії →

error[E0308]: mismatched types

error[E0308]: mismatched types Найчастіша помилка новачка: функція обіцяє String, а ти повертаєш &str (або навпаки). Дивись на два рядки під помилкою: компілятор пише expected і found — саме в цьому порядку.

📡 С.І.Д.: «Ти обіця[[g:в|ла]] мені відмичку, а простягаєш креслення відмички. Різні речі».

error[E0425]: cannot find value ... in this scope

error[E0425]: cannot find value ... in this scope Опечатка в імені або змінна оголошена в іншому блоці. Rust не бачить нічого поза {}, у яких оголошено.

📡 С.І.Д.: «Такого інструмента на верстаку немає. Перевір, як ти його назва[[g:в|ла]]».

cargo: command not found

cargo: command not found Тулчейн не встановлений або не в PATH. Постав: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh, тоді source "$HOME/.cargo/env". У devcontainer курсу Rust уже є — перевір, що ти в контейнері, а не на хості.

📡 С.І.Д.: «Кузні немає. Ти прийш[[g:ов|ла]] кувати в порожній двір».

cargo test каже 0 tests, хоча тест написаний

cargo test каже 0 tests, хоча тест написаний Тест не в модулі з #[cfg(test)], або забутий атрибут #[test] над функцією, або файл не той. Перевір обидва атрибути — вони обов'язкові.

📡 С.І.Д.: «Симулятор увімкнено, але випробовувати нічого. Ти не пода[[g:в|ла]] йому зразок».

warning: unused variable — і збірка все одно проходить

warning: unused variable — і збірка все одно проходить Це попередження, не помилка: Rust дозволяє зібратися, але каже, що щось зайве. Не ігноруй — часто це і є слід справжньої помилки в логіці. Якщо змінна потрібна «про запас», назви її _acc: підкреслення означає «знаю, що не використовую».

📡 С.І.Д.: «Компілятор не сварить — він показує пальцем. Подивись, куди».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР5 · Мертвий Лог до місії →

error[E0382]: borrow of moved value

error[E0382]: borrow of moved value Це та помилка, яку ти сьогодні лагодиш, — але вона вилізе ще раз, якщо поставити & не там. Дивись, куди вказує ^^^: це місце використання після переміщення, а не місце самого переміщення. Причина завжди вище.

📡 С.І.Д.: «Ти [[g:віддав|віддала]] карту й тягнешся до неї знову. Її вже немає в руках».

error[E0308]: mismatched types — expected &str, found &String

error[E0308]: mismatched types — expected &str, found &String (або навпаки) Класика першої правки: тип у сигнатурі змінили, а виклик ні (або навпаки). Найпростіше тримати &str у параметрі й &log на виклику, як у Етапі 3, — тоді компілятор зведе &String до &str сам.

📡 С.І.Д.: «Ми з тобою про одне й те саме, але різними словами. Домовмося про одні».

error[E0502]: cannot borrow ... as mutable because it is also borrowed as immutable

error[E0502]: cannot borrow ... as mutable because it is also borrowed as immutable Ти тримаєш & на значення й одночасно намагаєшся змінити його. Правило одне: багато читачів АБО один письменник. Найдешевше лікується звуженням області видимості — загорни читання у { }, щоб позика скінчилася до запису.

📡 С.І.Д.: «Двоє тримають один аркуш, і один із них хоче його переписати. Спершу відпустіть».

error[E0499]: cannot borrow ... as mutable more than once at a time

error[E0499]: cannot borrow ... as mutable more than once at a time Два &mut на одне значення живуть одночасно. Той самий рецепт: скорочуй життя першої позики, а не додавай .clone().

📡 С.І.Д.: «Два письменники, одне перо. Хтось мусить дописати перший».

cargo build зелений, а автогрейдер червоний

cargo build зелений, а автогрейдер червоний Майже завжди це .clone() замість запозичення або видалений другий log із format!. Компілятор такий код пропускає — він справді компілюється. Але задача ночі була не «щоб збиралося», а «щоб зрозуміти, хто чим володіє», і перевірка це розрізняє.

📡 С.І.Д.: «Ти обійш[[g:ов|ла]] Прикордонника, а не порозумі[[g:вся|лася]] з ним. Він пропустив — я ні».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР6 · Архітектура Ворога до місії →

error[E0004]: non-exhaustive patterns: ... not covered

error[E0004]: non-exhaustive patterns: ... not covered У match не покритий якийсь варіант enum. Це не причепка, а вся суть прийому: компілятор показує тобі стан, про який ти забу[[g:в|ла]]. Додай гілку — і не заклеюй дірку через _ => ..., бо тоді наступний забутий варіант пройде молча.

📡 С.І.Д.: «Ти описа[[g:в|ла]] не всю варту. Один вартовий лишився без інструкції».

error[E0428]: the name 'GuardNode' is defined multiple times

error[E0428]: the name 'GuardNode' is defined multiple times Класика рівня 3: структуру оголосили вдруге, замість того щоб додати поле до наявної. Один тип — одне оголошення.

📡 С.І.Д.: «Два креслення одного вузла. Яке з них справжнє?»

error[E0063]: missing field 'sensor' in initializer of 'GuardNode'

error[E0063]: missing field 'sensor' in initializer of 'GuardNode' Щойно з'явилося нове поле, кожен літерал GuardNode { ... } мусить його вказати. Це добра новина: компілятор сам перелічив тобі всі місця, які треба оновити. Пройди списком і допиши sensor: None.

📡 С.І.Д.: «Схема змінилася — а три вузли ще збудовані за старою».

error[E0308]: mismatched types — 'expected u8, found integer'

error[E0308]: mismatched types — 'expected u8, found integer' (та подібні) Alert(u8) тримає число до 255. Якщо підставляєш більше або інший числовий тип — компілятор зупинить. Тип варіанта — це теж контракт, і він теж навмисний.

📡 С.І.Д.: «Рівень тривоги в них однобайтовий. Двобайтовий підпис нас видасть».

thread 'main' panicked at 'called Option::unwrap() on a None value'

thread 'main' panicked at 'called Option::unwrap() on a None value' Єдина помилка з цього списку, яку компілятор не зловить: unwrap() компілюється завжди й падає в рантаймі. Саме тому в рівні 3 його немає — обидва рівні вкладеного Option обробляються match-ем.

📡 С.І.Д.: «Ось вона, порожнеча. Аварійна зупинка просто в них під носом — і підпис чужинця в їхньому журналі».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР7 · Мінне Поле до місії →

error[E0308]: mismatched types — 'expected Result<String, ReadLogError>, found String'

error[E0308]: mismatched types — 'expected Result<String, ReadLogError>, found String' Забутий Ok(...) на успішній гілці. Функція обіцяла Result, а ти повертаєш саме значення.

📡 С.І.Д.: «Ти простягаєш мені дані без конверта. Я не бачу, успіх це чи ні».

warning: unused Result that must be used

warning: unused Result that must be used Виклик, що повертає Result, проігнорований. Це попередження, а не помилка, — і саме тому небезпечне: код збереться, а провал зникне безслідно. Обробляй або свідомо пиши let _ = ....

📡 С.І.Д.: «Хтось повідомив про міну, а ти не прочита[[g:в|ла]] записки».

the ? operator can only be used in a function that returns Result

the ? operator can only be used in a function that returns Result (E0277) Класика рівня 2: ? поставили у функцію, яка повертає звичайне значення — найчастіше в main або в цикл обробки списку. У циклі ? не потрібен принципово: він зупинив би всю обробку через один битий файл.

📡 С.І.Д.: «Не тікай із поля через одну міну. Обійди її й іди далі».

test corrupted_file_returns_corrupted ... FAILED — а файл наче побитий

test corrupted_file_returns_corrupted ... FAILED — а файл наче побитий Фікстура створена текстовим редактором, який «полагодив» невалідний байт при збереженні. Роби її байтами: printf 'Hi\xff!' > fixtures/corrupted_log.bin — і перевір xxd fixtures/corrupted_log.bin.

📡 С.І.Д.: «Твоя міна виявилася муляжем. Редактор її обеззброїв».

Тест прав доступу проходить там, де мав би провалитися

Тест прав доступу проходить там, де мав би провалитися chmod 000 не діє на root, а в багатьох контейнерах процес запущений саме від root. Перевір whoami; якщо root — це не твоя помилка, і варіант 2 таблиці просто не відтворюється в цьому середовищі.

📡 С.І.Д.: «Замок є, але ти маєш ключ від усіх дверей. Перевір, хто ти в цій системі».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР8 · Пряма Ін'єкція до місії →

wat2wasm: error: unexpected token ")", expected ...

wat2wasm: error: unexpected token ")", expected ... Дужки. У .wat вони структурні, як у Lisp: кожен (func ...) мусить закритися, і редактор тут головний друг — став курсор на дужку й дивись, куди підсвітилася пара.

📡 С.І.Д.: «Речення без крапки. Машина чекає, чим ти [[g:закінчив|закінчила]] думку».

type mismatch in implicit return, expected [i32] but got []

type mismatch in implicit return, expected [i32] but got [] Функція обіцяла (result i32), а стек у кінці порожній: чи то забутий local.get, чи то інструкція зняла більше, ніж ти [[g:поклав|поклала]]. Порахуй руками: скільки кладу, скільки знімаю, що лишається.

📡 С.І.Д.: «Ти обіця[[g:в|ла]] машині число й простягаєш порожню руку».

RuntimeError: unreachable executed

RuntimeError: unreachable executed Заглушка unreachable лишилася в тілі функції. Це не збій — це навмисна пастка стартера: доки її не прибра[[g:в|ла]], модуль компілюється, але падає при виклику.

📡 С.І.Д.: «Ти лиши[[g:в|ла]] в кресленні напис «тут нічого немає». Машина прочитала буквально».

TypeError: Failed to fetch / CORS request not http

TypeError: Failed to fetch / CORS request not http Сторінку відкрито як file://, без сервера. Підніми python3 -m http.server 8080 і зайди через http://localhost:8080/.

📡 С.І.Д.: «Ти стукаєш у двері, яких для браузера не існує. Дай йому адресу».

RuntimeError: memory access out of bounds

RuntimeError: memory access out of bounds (рівень 3) Звернення за межі виділеної сторінки. Це правильна робота пісочниці, а не поломка: одна сторінка — 65 536 байтів, і адреса 70000 за нею. Саме цього не станеться в ЛР9, і саме тому WASM пускають у браузер.

📡 С.І.Д.: «Стіна є, і вона тримає. Мені це, зізнаюся, подобається».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР9 · Розтин Системи до місії →

objdump: command not found / wasm-objdump: command not found

objdump: command not found / wasm-objdump: command not found Не встановлені binutils (перший) або WABT (другий). У devcontainer курсу обидва є — перевір, що ти в контейнері, а не на хості.

📡 С.І.Д.: «Скальпеля немає. Розтин без інструмента — просто розглядання».

x86.txt майже порожній, у ньому лише кілька рядків

x86.txt майже порожній, у ньому лише кілька рядків Забуте -c: без нього gcc намагається зібрати повну програму, не знаходить main і падає, а objdump читає стару або порожню .o. Перевір, що algo_x86.o щойно створений (ls -la).

📡 С.І.Д.: «Ти [[g:приніс|принесла]] мені порожній стіл і кажеш, що тіла не було».

У x86.txt немає ні push %rbp, ні окремої функції

У x86.txt немає ні push %rbp, ні окремої функції Збірка пішла з оптимізаціями — компілятор зробив inline і викинув пролог. Для цієї роботи потрібне саме -O0.

📡 С.І.Д.: «Компілятор виявився надто послужливим і прибрав усе, що ми прийшли дивити».

WASM-збірка падає: wasm32 target not found / emcc: command not found

WASM-збірка падає: wasm32 target not found / emcc: command not found Основний шлях — clang з таргетом wasm32 (шлях Б у build.sh): він дає самодостатній модуль без імпортів, і саме такий очікує автотест. Emscripten (шлях А) підходить лише з прапорцем -sSTANDALONE_WASM — без нього модуль вимагає середовища Emscripten і не інстанціюється, тобто автотест упаде. Якщо clang без таргета wasm32 — не вигадуй обхід, став пакет lld або бери шлях А саме зі STANDALONE_WASM і зазнач це в comparison.md.

📡 С.І.Д.: «Дві дороги до того самого столу. Іди тією, що відчинена».

Порівняння вийшло «WASM менший, отже швидший»

Порівняння вийшло «WASM менший, отже швидший» Найчастіша змістова помилка ночі, а не технічна. Розмір файлу не є мірою швидкодії: кодування WASM щільніше, а .o несе метадані ELF. Висновок «менший ≠ швидший» і є правильною відповіддю.

📡 С.І.Д.: «Тонша книжка не означає швидше читання. Порівнюй те, що можна порівняти».

Решта помилок курсу — у «Коли щось пішло не так».

ЛР10 · Звільнення до місії →

Error: rust-wasm-bindgen version mismatch

Error: rust-wasm-bindgen version mismatch (або it looks like the Rust project used to create this wasm file had a different version) Версія в Cargo.toml і версія CLI розійшлися. Або постав CLI тієї самої версії (cargo install -f wasm-bindgen-cli --version 0.2.92), або лиши ="=0.2.92" у Cargo.toml і не оновлюй. Це найчастіша поломка ночі.

📡 С.І.Д.: «Дві половини ядра з різних креслень не зійдуться. Я це знаю краще за всіх».

Сторінка відкривається, консоль порожня, нічого не працює

Сторінка відкривається, консоль порожня, нічого не працює Зібрано не з --target web. Ціль bundler (типова) розрахована на webpack і в браузері напряму не запуститься — причому без помилки. Перезбери з --target web.

📡 С.І.Д.: «Ти [[g:зібрав|зібрала]] мене для іншої машини. Тиша — це не відмова, це непорозуміння».

error: cannot produce cdylib

error: cannot produce cdylib / у pkg/ немає .wasm Забутий [lib] crate-type = ["cdylib"] у Cargo.toml.

📡 С.І.Д.: «Кузня видала заготовку, а не ядро. Скажи їй, що саме кувати».

TypeError: Failed to fetch під час init()

TypeError: Failed to fetch під час init() Знову file:// замість сервера, або pkg/ лежить не там, куди дивиться index.html. Перевір шлях в import init from './pkg/sid_core.js'.

📡 С.І.Д.: «Двері є, але не за тією адресою, яку ти [[g:назвав|назвала]]».

Два хеші зійшлися з першого разу, без чистого каталогу

Два хеші зійшлися з першого разу, без чистого каталогу (рівень 3) Це не успіх, а хибний результат: друга збірка взяла артефакт із шарів Docker або зі старої pkg/. Прибери pkg/ і target/ між запусками — і збери ще раз.

📡 С.І.Д.: «Два відбитки одного пальця — доказ. Двічі показаний той самий відбиток — ні».

Решта помилок курсу — у «Коли щось пішло не так».