◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-04-30中級

Rork の『undefined is not an object』エラーを最短で特定する方法

Rorkで頻発する『undefined is not an object (evaluating ...)』エラーの読み解き方と、典型的な5つの原因をコード付きで解説します。Hermesのスタックが読みにくいときのデバッグ手順もまとめています。

Rork585Hermes9デバッグ22エラー対処3React Native239

Rork で生成されたコードを少し書き換えたら、いきなり赤い画面に「undefined is not an object (evaluating 'user.profile.name')」と表示された経験はありませんか。私も最初は「null チェックを足せば直るんでしょ」と高をくくっていたのですが、実際には参照しているプロパティそのものではなく、その上のオブジェクトが期待と違う形で返ってきている、というケースがほとんどでした。

このエラーは Hermes(Rork が標準で使う JavaScript エンジン)が「アクセスしようとした親が undefined だった」と教えてくれているメッセージです。原因は意外と少ないパターンに収束しますので、闇雲に ?. を足す前に、まず読み方とよくある落とし穴を押さえておくと、再発をぐっと減らせます。

まずエラーメッセージの『括弧の中』を必ず読む

このエラーで一番もったいないのが、undefined is not an object の文字だけ見て焦って手当てしてしまうことです。注目すべきはその後ろの (evaluating 'user.profile.name') の部分で、Hermes がどの式を評価したときに失敗したかをかなり正確に教えてくれます。

ERROR  undefined is not an object (evaluating 'user.profile.name')

この場合、問題は user.profile.name の評価ですが、Hermes の判定基準は「name を取り出そうとしたときに user.profile が undefined だった」です。つまり犯人は profile プロパティであって、user 自体や name ではない可能性が高い、ということになります。

デバッグの第一歩は『1つ手前で止めて中身を見る』こと

Rork で動かしているとスタックトレースが minify されたファイル名(例: index.bundle:135432)になりがちで、行番号からは原因が辿りにくいです。私は次のように一段ずつ console.log を仕込む方法を使っています。

// app/screens/Profile.tsx
function ProfileScreen({ route }) {
  const userId = route.params?.userId;
 
  // ❌ いきなり最深部にアクセスしてエラー
  // return <Text>{user.profile.name}</Text>;
 
  // ✅ 段階的に中身を確認
  const { data: user } = useUser(userId);
  console.log('[Profile] user:', user);
  console.log('[Profile] user.profile:', user?.profile);
 
  if (!user?.profile) {
    return <Text>プロフィールを読み込み中...</Text>;
  }
 
  return <Text>{user.profile.name}</Text>;
}

期待出力は [Profile] user: { id: 1, name: '...' } のように出るはずなのに、実際には [Profile] user.profile: undefined と出る、というように犯人がはっきり見えます。?. を足すこと自体は対症療法ですので、まず「なぜ profile が来ていないのか」を必ず確認してから防御コードを書くようにしています。

典型的な原因 5 つと、それぞれの直し方

1. API レスポンスのキー名が想定と違う

これが一番多いパターンだと感じています。バックエンド側で profile を userProfile にリネームしたのに、フロント側だけが古い名前のまま、という事故です。

// ❌ レスポンス構造が変わったのに気付いていない
const { data } = await fetch('/api/me').then(r => r.json());
return data.profile.name;  // → undefined is not an object
 
// ✅ レスポンスを一度確認するクセをつける
const json = await fetch('/api/me').then(r => r.json());
console.log('me response:', json);
const profile = json.user?.profile ?? json.profile ?? null;
if (!profile) throw new Error('profile が API から返ってきませんでした');
return profile.name;

2. useState の初期値が undefined のまま render される

// ❌ 初期値なしの useState に、初回render で深いアクセスする
const [user, setUser] = useState();  // 初期値が undefined
useEffect(() => {
  fetchUser().then(setUser);
}, []);
return <Text>{user.email}</Text>;  // ← 初回 render で爆発
 
// ✅ 初期値を設定し、未ロード時の表示を分ける
const [user, setUser] = useState(null);
useEffect(() => { fetchUser().then(setUser); }, []);
if (!user) return <ActivityIndicator />;
return <Text>{user.email}</Text>;

3. ネストした props の destructuring 忘れ

ナビゲーション周りでよく踏みます。useRoute や useLocalSearchParams の戻り値はキーが存在しないと undefined を返します。

// ❌ params が空のときに userId を取り出そうとして爆発
const { params: { userId } } = useRoute();
 
// ✅ 一段ずつ optional chaining で受ける
const route = useRoute();
const userId = route.params?.userId;
if (!userId) {
  // 開発中は throw すると気付きやすい
  if (__DEV__) console.warn('userId がありません', route);
  return null;
}

4. ネイティブモジュールの import を忘れている

@react-native-async-storage/async-storage のように、Expo prebuild が必要なライブラリで起こりがちです。Rork のプレビュー上は動いていても、実機ビルドだとモジュールが解決されず undefined のまま import される、という現象です。

import AsyncStorage from '@react-native-async-storage/async-storage';
 
// 実機で undefined になっていないかを開発時に確認
if (__DEV__ && !AsyncStorage) {
  console.error('AsyncStorage が読み込めていません。expo prebuild を確認してください');
}

EAS Build のログに Could not find module の警告が出ていないかも合わせて確認すると、原因の切り分けが早くなります。

5. useEffect で setState する前に値を参照している

非同期で取得した値を、まだ存在しない段階で読みに行ってしまうケースです。

// ❌ items がまだ未定義の段階で .map にかかる
useEffect(() => {
  fetch('/api/items').then(r => r.json()).then(setItems);
}, []);
return items.map(i => <Item key={i.id} item={i} />);
 
// ✅ 配列なら空配列で初期化しておくのが安全
const [items, setItems] = useState([]);  // ← undefined ではなく []
return items.map(i => <Item key={i.id} item={i} />);

配列の場合は useState([])、オブジェクトの場合は useState(null) にして「未ロード」と「中身が空」を区別できる状態を作るのが、私の中での定石です。

それでも特定できないときの最終手段

これらをチェックしても直らない場合、Hermes のスタックトレースの読み方を一段深めるのが有効です。Rork から Companion アプリに繋ぐと開発ビルドで sourcemap が有効になり、minify 前のファイル名と行番号が出るようになります。さらに、エラーが画面のどこで起きているかを切り分けるために、コンポーネントツリーを ErrorBoundary で部分的に囲み、原因の枝を機械的に絞り込む方法もあります。

function SafeBox({ name, children }) {
  return (
    <ErrorBoundary fallback={<Text>{name} で失敗しました</Text>}>
      {children}
    </ErrorBoundary>
  );
}
 
// ✅ 怪しい枝を1つずつ ErrorBoundary で包んで切り分ける
<SafeBox name="ProfileHeader">
  <ProfileHeader user={user} />
</SafeBox>
<SafeBox name="PostsList">
  <PostsList userId={user?.id} />
</SafeBox>

「画面全体が落ちる」を「特定のセクションだけが落ちる」に変えると、後の console.log もピンポイントで仕掛けられるようになります。

再発を減らすための日々の習慣

このエラーを根本的に減らすには、TypeScript で API レスポンスの型を厳密に書き、undefined の可能性を型レベルで強制するのが一番効きます。zod などのバリデーションを通せば、レスポンス形が変わったときにフロントの型と実体がずれることを防げます。型まわりのつまずきは TypeScript の型エラーが消えないときの直し方 にもまとめていますので、合わせて読んでみてください。React Native ランタイムで起きる他のエラーパターンも整理した React Native / Expo のランタイムエラー修正ガイド も参考になるはずです。

全体を振り返って

このエラーに出会ったら、まず (evaluating '...') の式をそのまま読み、一段手前のオブジェクトの実体を console.log で確認する、というクセを付けてみてください。?. を足して赤画面が消えても、データの形がそもそも想定と違っていれば、別の場所で必ず再発します。今日の自分のコードに useState() で初期値を省略している箇所がないかだけでも、ぜひ一度 grep してみると、思わぬ地雷が見つかるかもしれません。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ 開発ツール2026-10-13
リリース前に、書き出した Expo バンドルの中から自分の鍵を探してみる
ソースに鍵がなくても、出来上がったアプリの中に鍵が残ることがあります。Expo SDK 57 で実際に expo export を実行し、バンドルの中身を grep と 60 行ほどの Node スクリプトで調べて、見つかる鍵と見つからない鍵の違いを確かめました。
⬡ 開発ツール2026-09-04
EAS の secret は「アプリに入れない」設定ではありません — 接頭辞と可視性を別々に決める
EXPO_PUBLIC_ の接頭辞は成果物に入るかを決め、EAS の可視性は誰が読めるかを決めます。二つを重ねたときに OTA 更新でだけ値が消える筋道と、出荷前に自分の手で確かめる手順をまとめました。
⬡ 開発ツール2026-08-22
一括置換は全ファイル成功しました。壊れたのは、消さなかった行のほうです
生成コードに一括置換をかけると、一致した行ではなく隣の行が壊れます。運用中のプロジェクトで実際に起きた破損と、置換の不変条件を検査する20行のガードスクリプトをまとめました。